[
  {
    "path": ".gitignore",
    "content": "# OS files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trash*\nIcon?\nethumbs.db\nThumbs.db\n*.tmp\n\n# Make\nCMakeCache.txt\nCMakeFiles\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\ntags\nMakefile.in\n\n# Testing\ntesting/data\n*~\n\n# Vim\n*.swp\n\n# Object files\n*.o\n*.lo\n*.a\n\n# Executables\n*.exe\n*.out\n*.app\n*.la\n\n# Misc (?)\nm4/*\nconfigure\nconfigure_aux\n!m4/pkg.m4\naclocal.m4\nconfig.h*\nconfig.log\nconfig.status\nstamp-h1\nautom4te.cache\nlibtoxcore.pc\nlibtoxav.pc\nlibtool\n.deps\n.libs\n.dirstamp\nbuild/\n\n#kdevelop\n.kdev/\n*.kdev*\n\n# Netbeans\nnbproject\n\n# astyle\n*.orig\n\n# Android buildscript\nandroid-toolchain-*\ntoxcore-android-*\n\n# cscope files list\ncscope.files\n\n# rpm\ntox.spec\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: required\ndist: trusty\nlanguage: c\ncompiler:\n  - gcc\n  - clang\n\nbefore_script:\n  - sudo add-apt-repository ppa:avsm/ocaml42+opam12 -y\n  - sudo apt-get update -qq\n  - sudo apt-get install ocaml opam astyle -qq\n  - sudo apt-get install libconfig-dev libvpx-dev libopus-dev check -qq\n  # build apidsl\n  - git clone https://github.com/iphydf/apidsl\n  - cd apidsl\n  - export OPAMYES=1\n  - opam init\n  - opam install ocamlfind ppx_deriving menhir\n  - eval `opam config env`\n  - make -j3\n  - cd ..\n  # install sodium, as it's not in Ubuntu Trusty\n  - git clone git://github.com/jedisct1/libsodium.git\n  - cd libsodium\n  - git checkout tags/1.0.8\n  - ./autogen.sh\n  - ./configure\n  - make -j3\n  - sudo make install\n  - cd ..\n  - sudo ldconfig\n\nscript:\n  # check if toxcore.h and toxav.h match apidsl tox.in.h and toxav.in.h\n  # tox.h\n  - ./apidsl/_build/apigen.native ./other/apidsl/tox.in.h > tox.h\n  - astyle --options=./other/astyle/astylerc tox.h\n  - diff -u tox.h ./toxcore/tox.h\n  # toxav.h\n  - ./apidsl/_build/apigen.native ./other/apidsl/toxav.in.h > toxav.h\n  - astyle --options=./other/astyle/astylerc toxav.h\n  - diff -u toxav.h ./toxav/toxav.h\n  # build toxcore and run tests\n  - ./autogen.sh\n  - CFLAGS=\"-Ofast -Wall -Wextra\" ./configure --enable-daemon --enable-ntox\n  - make\n  - make check\n  - cat build/test-suite.log\n  - make dist\n\nnotifications:\n  email: false\n\n  irc:\n    channels:\n      - \"chat.freenode.net#tox-dev\"\n    on_success: always\n    on_failure: always\n"
  },
  {
    "path": "COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "DONATORS",
    "content": "Minnesota > Florida\nvdo <vdo@greyfaze.net>\nSpitfire is best technicolor horse.\nif bad people don't hate you, you're doing something wrong\nPinkie Pie is best pony.\nJRS was here\nqTox is so bloated it doesn't even fit in a 64-bit address space\n"
  },
  {
    "path": "INSTALL.md",
    "content": "#Install Instructions\n\n- [Installation](#installation)\n  - [Unix like](#unix)\n    - [Quick install](#quick-install)\n    - [Build manually](#build-manually)\n      - [Compile toxcore](#compile-toxcore)\n  - [OS X](#osx)\n    - [Homebrew](#homebrew)\n    - [Non-Homebrew](#non-homebrew)\n  - [Windows](#windows)\n    - [Cross-Compile](#windows-cross-compile)\n      - [Setting up a VM](#windows-cross-compile-vm)\n      - [Setting up the environment](#windows-cross-compile-environment)\n      - [Compiling](#windows-cross-compile-compiling)\n    - [Native](#windows-native)\n- [Additional](#additional)\n  - [Advanced configure options](#aconf)\n  - [A/V support](#av)\n    - [libtoxav](#libtoxav)\n  - [Bootstrap daemon](#bootstrapd)\n  - [nTox](#ntox)\n\n<a name=\"installation\" />\n##Installation\n\n<a name=\"unix\" />\n###Most Unix like OSes:\n\n#### Quick install:\n\nOn Gentoo:\n```\n# layman -f && layman -a tox-overlay && emerge net-libs/tox\n```\n\nAnd you're done `:)`</br>\nIf you happen to run some other distro which isn't made for compiling, there are steps below:\n\n#### Build manually\n\nBuild dependencies:\n\nNote: package fetching commands may vary by OS.\n\nOn Ubuntu `< 15.04` / Debian `< 8`:\n\n```bash\nsudo apt-get install build-essential libtool autotools-dev automake checkinstall check git yasm\n```\n\nOn Ubuntu `>= 15.04` / Debian `>= 8`:\n```bash\nsudo apt-get install build-essential libtool autotools-dev automake checkinstall check git yasm libsodium13 libsodium-dev\n```\n\nOn Fedora:\n\n```bash\ndnf groupinstall \"Development Tools\"\ndnf install libtool autoconf automake check check-devel\n```\nUsing ``dnf install @\"Development Tools\"`` is also valid and slightly shorter / cleaner way. ``@\"Rpm Development Tools\"``  would carry the remaining dependencies listed here.\n\nOn SunOS:\n\n```pfexcec\npkg install autoconf automake gcc-47\n```\nOn FreeBSD 10+:\n\n```tcsh\npkg install net-im/tox\n```\nNote, if you install from ports select NaCl for performance, and sodium if you want it to be portable.\n\n**For A/V support, also install the dependences listed in the [libtoxav](#libtoxav) section.** Note that you have to install those dependencies **before** compiling `toxcore`.\n\nYou should get and install [libsodium](https://github.com/jedisct1/libsodium). If you have installed `libsodium` from repo, ommit this step, and jump directly to [compiling toxcore](#compile-toxcore):\n```bash\ngit clone https://github.com/jedisct1/libsodium.git\ncd libsodium\ngit checkout tags/1.0.3\n./autogen.sh\n./configure && make check\nsudo checkinstall --install --pkgname libsodium --pkgversion 1.0.0 --nodoc\nsudo ldconfig\ncd ..\n```\n\n\nOr if checkinstall is not easily available for your distribution (e.g., Fedora),\nthis will install the libs to /usr/local/lib and the headers to /usr/local/include:\n\n```bash\ngit clone https://github.com/jedisct1/libsodium.git\ncd libsodium\ngit checkout tags/1.0.3\n./autogen.sh\n./configure\nmake check\nsudo make install\ncd ..\n```\n\nIf your default prefix is ``/usr/local`` and you happen to get an error that says ``\"error while loading shared libraries: libtoxcore.so.0: cannot open shared object file: No such file or directory\"``, then you can try running ``sudo ldconfig``. If that doesn't fix it, run:\n\n```bash\necho '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf.d/locallib.conf\nsudo ldconfig\n```\n\nYou may run into a situation where there is no ``/etc/ld.so.conf.d`` directory. You could either create it manually, or append path to local library to ``ld.so.conf``:\n\n```bash\necho '/usr/local/lib/' | sudo tee -a /etc/ld.so.conf \nsudo ldconfig\n```\n\n##### Compile toxcore\n\nThen clone this repo, generate makefile, and install `toxcore` system-wide:\n```bash\ngit clone https://github.com/irungentoo/toxcore.git\ncd toxcore\nautoreconf -i\n./configure\nmake\nsudo make install\n```\n\n\n<a name=\"osx\" />\n###OS X:\n\nYou need the latest XCode with the Developer Tools (Preferences -> Downloads -> Command Line Tools).\nThe 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.\n\n**Note: OS X users can also install Toxcore using [osx_build_script_toxcore.sh](other/osx_build_script_toxcore.sh)**\n\nThere 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.\n<a name=\"homebrew\" />\n####Homebrew:\nTo install from the formula:\n```bash\nbrew tap Tox/tox\nbrew install --HEAD libtoxcore\n```\n\nTo do it manually:\n```\nbrew install libtool automake autoconf libsodium check\n```\nThen clone this repo and generate makefile:\n```bash\ngit clone https://github.com/irungentoo/toxcore.git\ncd toxcore\nautoreconf -i\n./configure\nmake\nmake install\n```\n\nIf execution fails with errors like \"dyld: Library not loaded: /opt/tox-im/lib/libtoxcore.0.dylib\", you may need to specify libsodium path:\n\nDetermine paths:\n```\nbrew list libsodium\n```\n\nConfigure include and lib folder and build again:\n```bash\n./configure --with-libsodium-headers=/usr/local/Cellar/libsodium/1.0.0/include/ --with-libsodium-libs=/usr/local/Cellar/libsodium/1.0.0/lib/\nmake\nmake install\n```\n\n\n<a name=\"non-homebrew\" />\n####Non-homebrew:\n\nGrab the following packages:\n  * https://gnu.org/software/libtool/\n  * https://gnu.org/software/autoconf/\n  * https://gnu.org/software/automake/\n  * https://github.com/jedisct1/libsodium\n  * http://check.sourceforge.net/\n  * http://yasm.tortall.net/Download.html (install before libvpx)\n  * https://code.google.com/p/webm/downloads/list\n  * http://www.opus-codec.org/downloads/\n  * http://www.freedesktop.org/wiki/Software/pkg-config/\n\nMacports: (https://www.macports.org/)\nAll toxcore dependencies can be installed from MacPorts. This is often easier on PowerPC Macs,\nand any version of OS X prior to 10.6, since Homebrew is supported on 10.6 and up, but not much\n(or at all) on older systems. A few packages have slightly different names from the corresponding\npackage in Debian.\n\nSame: libtool autoconf automake libsodium check yasm\nDifferent: libvpx (webm) libopus pkgconfig gettext\n\n(the libintl, from gettext, built into OS X 10.5 is missing libintl_setlocale, but the Macports build has it)\n\nVerify where libintl is on your system: (MacPorts puts it in /opt/local)\n```\nfor d in /usr/local/lib /opt/local/lib /usr/lib /lib; do ls -l $d/libintl.*; done\n```\n\nCheck if that copy has libintl_setlocale:\n```\nnm /opt/local/lib/libintl.8.dylib | grep _libintl_setlocale\n```\n\nCertain other tools may not be installed, or outdated, and should also be installed from MacPorts for simplicity: git cmake\n\nIf 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:\n```\nln -s /opt/local/lib/libsodium.dylib /usr/local/lib/libsodium.dylib\n```\n\nMuch 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)\n\npkg-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).\n\nUncompress and install them all. Make sure to follow the README as the instructions change, but they all follow the same pattern below:\n\n```bash\n./configure\nmake\nsudo make install\n```\n\nCompiling and installing Tox Core\n\n```bash\ncd toxcore\nautoreconf -i\n./configure (OS X 10.5 specific)\n./configure CC=\"gcc -arch ppc -arch i386\" CXX=\"g++ -arch ppc -arch i386\" CPP=\"gcc -E\" CXXCPP=\"g++ -E\"\nmake\nmake install (OS X 10.5 specific)\nshould be: sudo make install\nIf it worked, you should have all the toxcore dylibs in /usr/local/lib: (besides the four below, the rest are symlinks to these)\n$ ls -la /usr/local/lib/libtox*.dylib\nlibtoxav.0.dylib\nlibtoxcore.0.dylib\nlibtoxdns.0.dylib\nlibtoxencryptsave.0.dylib\nto check what CPU architecture they're compiled for:\n$ lipo -i /usr/local/lib/libtoxencryptsave.0.dylib\nYou should now be able to move on to compiling Toxic/Venom or some other client application\nThere 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.\n```\n\nIf 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;\n\n```\n./configure --with-libsodium-headers=/usr/local/include/ --with-libsodium-libs=/usr/local/lib\n```\n\nEnsure you set the locations correctly depending on where you installed libsodium on your computer.\n\nIf there is a problem with opus (for A/V) and you don't get a libtoxav, then try to set the pkg-config environment variable beforehand:\n\n```\nexport PKG_CONFIG_PATH=/usr/local/lib/pkgconfig\n```\n\n<a name=\"windows\" />\n###Windows:\n\n<a name=\"windows-cross-compile\" />\n\n####Cross-compile\n\nIt's a bit challenging to build Tox and all of its dependencies nativly on Windows, so we will show an easier, less error and headache prone method of building it -- cross-compiling.\n\n<a name=\"windows-cross-compile-vm\" />\n#####Setting up a VM\n\nWe will assume that you don't have any VM running Linux around and will guide you from the ground up.\n\nFirst, you would need to get a virtual machine and a Linux distribution image file.\n\nFor a virtual machine we will use VirtualBox. You can get it [here](https://www.virtualbox.org/wiki/Downloads).\n\nFor a Linux distribution we will use Lubuntu 14.04 32-bit, which you can get [here](https://help.ubuntu.com/community/Lubuntu/GetLubuntu).\n\nAfter you have those downloaded, install the VirtualBox and create a VM in it. The default of 512mb of RAM and 8gb of dynamically-allocated virtual hard drive would be enough.\n\nWhen you have created the VM, go into its **Settings** -> **System** -> **Processor** and add some cores, if you have any additional available, for faster builds.\n\nThen, go to **Settings** -> **Storage**, click on **Empty** under **Controller: IDE**, click on the little disc icon on the right side of the window, click on **Choose a virtual CD/DVD disk file** and select the downloaded Lubuntu image file.\n\nStart the VM and follow the installation instructions.\n\nAfter Lubuntu is installed and you have booted into it, in VirtualBox menu on top of the window select **Devices** -> **Insert Guest Additions CD image...**.\n\nOpen terminal from **Lubuntu's menu** -> **Accessories**.\n\nExecute:\n```bash\nsudo apt-get update\nsudo apt-get install build-essential -y\ncd /media/*/*/\nsudo ./VBoxLinuxAdditions.run\n```\n\nAfter that, create a folder called `toxbuild` somewhere on your Windows system. The go to **Devices** -> **Shared Folders Settings...** in the VirtualBox menu, add the `toxbuild` folder there and set **Auto-mount** and **Make Permanent** options.\n\nExecute:\n```bash\nsudo adduser `whoami` vboxsf\n```\nNote the use of a [grave accent](http://en.wikipedia.org/wiki/Grave_accent) instead of an apostrophe.\n\nThen just reboot the system with:\n```bash\nsudo reboot\n```\n\nAfter the system is booted, go to **Devices** -> **Shared Clipboard** and select **Bidirectional**. Now you will be able to copy-paste text between the host and the guest systems.\n\nNow that the virtual machine is all set up, let's move to getting build dependencies and setting up environment variables.\n\n<a name=\"windows-cross-compile-environment\" />\n#####Setting up the environment\n\nFirst we will install all tools that we would need for building:\n```bash\nsudo apt-get install build-essential libtool autotools-dev automake checkinstall check git yasm pkg-config mingw-w64 -y\n```\n\nThen we will define a few variables, **depending on which you will build either 32-bit or 64-bit Tox**.\n\nFor 32-bit Tox build, do:\n```bash\nWINDOWS_TOOLCHAIN=i686-w64-mingw32\nLIB_VPX_TARGET=x86-win32-gcc\n```\n\nFor 64-bit Tox build, do:\n```bash\nWINDOWS_TOOLCHAIN=x86_64-w64-mingw32\nLIB_VPX_TARGET=x86_64-win64-gcc\n```\n\nThis is the only difference between 32-bit and 64-bit build procedures.\n\nFor speeding up the build process do:\n```\nMAKEFLAGS=j$(nproc)\nexport MAKEFLAGS\n```\n\nAnd let's make a folder where we will be building everything at\n```bash\ncd ~\nmkdir prefix\ncd prefix\nPREFIX_DIR=$(pwd)\ncd ..\nmkdir build\ncd build\n```\n\n<a name=\"windows-cross-compile-compiling\" />\n#####Compiling\n\nNow we will build libraries needed for audio/video: VPX and Opus.\n\nVPX:\n```bash\ngit clone https://chromium.googlesource.com/webm/libvpx\ncd libvpx\ngit checkout tags/v1.3.0\nCROSS=\"$WINDOWS_TOOLCHAIN\"- ./configure --target=\"$LIB_VPX_TARGET\" --prefix=\"$PREFIX_DIR\" --disable-examples --disable-unit-tests --disable-shared --enable-static\nmake\nmake install\ncd ..\n```\n\nOpus:\n```bash\nwget http://downloads.xiph.org/releases/opus/opus-1.1.tar.gz\ntar -xf opus-1.1.tar.gz\ncd opus-1.1\n./configure --host=\"$WINDOWS_TOOLCHAIN\" --prefix=\"$PREFIX_DIR\" --disable-extra-programs --disable-doc --disable-shared --enable-static\nmake\nmake install\ncd ..\n```\n\nNow we will build sodium crypto library:\n```bash\ngit clone https://github.com/jedisct1/libsodium/\ncd libsodium\ngit checkout tags/1.0.3\n./autogen.sh\n./configure --host=\"$WINDOWS_TOOLCHAIN\" --prefix=\"$PREFIX_DIR\" --disable-shared --enable-static\nmake\nmake install\ncd ..\n```\n\nAnd finally we will build Tox:\n```bash\ngit clone https://github.com/irungentoo/toxcore\ncd toxcore\n./autogen.sh\n./configure --host=\"$WINDOWS_TOOLCHAIN\" --prefix=\"$PREFIX_DIR\" --disable-ntox --disable-tests --disable-testing --with-dependency-search=\"$PREFIX_DIR\" --disable-shared --enable-static\nmake\nmake install\ncd ..\n```\n\nThen we make Tox shared library:\n```bash\ncd \"$PREFIX_DIR\"\nmkdir tmp\ncd tmp\n$WINDOWS_TOOLCHAIN-ar x ../lib/libtoxcore.a\n$WINDOWS_TOOLCHAIN-ar x ../lib/libtoxav.a\n$WINDOWS_TOOLCHAIN-ar x ../lib/libtoxdns.a\n$WINDOWS_TOOLCHAIN-ar x ../lib/libtoxencryptsave.a\n$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\n```\n\nAnd we will copy it over to the `toxbuild` directory:\n```bash\nmkdir -p /media/sf_toxbuild/release/lib\ncp libtox.dll.a /media/sf_toxbuild/release/lib\nmkdir -p /media/sf_toxbuild/release/bin\ncp libtox.dll /media/sf_toxbuild/release/bin\nmkdir -p /media/sf_toxbuild/release/include\ncp -r ../include/tox /media/sf_toxbuild/release/include\n```\n\nThat's it. Now you should have `release/bin/libtox.dll`, `release/bin/libtox.dll.a` and `release/include/tox/<headers>` in your `toxbuild` directory on the Windows system.\n\n<a name=\"windows-native\" />\n####Native\n\nNote that the Native instructions are incomplete, in a sense that they miss instructions needed for adding audio/video support to Tox. You also might stumble upon some unknown MinGW+msys issues while trying to build it.\n\nYou should install:\n  - [MinGW](http://sourceforge.net/projects/mingw/)\n\nWhen installing MinGW, make sure to select the MSYS option in the installer.\nMinGW 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.\n\nFirst download the source tarball from https://download.libsodium.org/libsodium/releases/ and build it.\nAssuming that you got the libsodium-1.0.0.tar.gz release:\n```cmd\ntar -zxvf libsodium-1.0.0.tar.gz\ncd libsodium-1.0.0\n./configure\nmake\nmake install\ncd ..\n```\n\nYou 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.\n\nNext, 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.\n\nAssuming that you now have the sources in the toxcore directory:\n\n```cmd\ncd toxcore\nautoreconf -i\n./configure\nmake\nmake install\n```\n\n<a name=\"Clients\" />\n####Clients:\nWhile [Toxic](https://github.com/tox/toxic) is no longer in core, a list of Tox clients are located in our [wiki](https://wiki.tox.chat/doku.php?id=clients)\n\n\n\n\n\n<a name=\"additional\" />\n##Additional\n\n\n\n<a name=\"aconf\" />\n###Advanced configure options:\n\n  - --prefix=/where/to/install\n  - --with-libsodium-headers=/path/to/libsodium/include/\n  - --with-libsodium-libs=/path/to/sodiumtest/lib/\n  - --enable-silent-rules less verbose build output (undo: \"make V=1\")\n  - --disable-silent-rules verbose build output (undo: \"make V=0\")\n  - --disable-tests build unit tests (default: auto)\n  - --disable-av disable A/V support (default: auto) see: [libtoxav](#libtoxav)\n  - --enable-ntox build nTox client (default: no) see: [nTox](#ntox)\n  - --enable-daemon build DHT bootstrap daemon (default=no) see: [Bootstrap daemon](#bootstrapd)\n  - --enable-shared[=PKGS]  build shared libraries [default=yes]\n  - --enable-static[=PKGS]  build static libraries [default=yes]\n\n\n<a name=\"av\" />\n###A/V support:\n\n<a name=\"libtoxav\" />\n####libtoxav:\n\n'libtoxav' is needed for A/V support and it's enabled by default. You can disable it by adding --disable-av argument to ./configure script like so:\n```bash\n./configure --disable-av\n```\n\nThere are 2 dependencies required for libtoxav: libopus and libvpx. If they are not installed A/V support is dropped.\n\nInstall on fedora:\n```bash\nyum install opus-devel libvpx-devel\n```\n\nInstall on ubuntu:\n```bash\nsudo apt-get install libopus-dev libvpx-dev pkg-config\n```\nIf you get the \"Unable to locate package libopus-dev\" message, add the following ppa and try again:\n```bash\nsudo add-apt-repository ppa:ubuntu-sdk-team/ppa && sudo apt-get update && sudo apt-get dist-upgrade\n```\n\nInstall from source (example for most unix-like OS's):\n\nlibvpx:\n```bash\ngit clone https://chromium.googlesource.com/webm/libvpx\ncd libvpx\n./configure\nmake -j3\nsudo make install\ncd ..\n```\n\nlibopus:\n```bash\nwget http://downloads.xiph.org/releases/opus/opus-1.0.3.tar.gz\ntar xvzf opus-1.0.3.tar.gz\ncd opus-1.0.3\n./configure\nmake -j3\nsudo make install\ncd ..\n```\n\n<a name=\"bootstrapd\" />\n###Bootstrap daemon:\n\nDaemon is disabled by default. You can enable it by adding --enable-daemon argument to ./configure script like so:\n```bash\n./configure --enable-daemon\n```\nThere is one dependency required for bootstrap daemon: `libconfig-dev` >= 1.4.\n\nInstall on fedora:\n```bash\nyum install libconfig-devel\n```\n\nInstall on ubuntu:\n```bash\nsudo apt-get install libconfig-dev\n```\n\nOS X homebrew:\n```\nbrew install libconfig\n```\nOS X non-homebrew:\nGrab the following [package](http://www.hyperrealm.com/libconfig/), uncompress and install\n\nSee this [readme](other/bootstrap_daemon/README.md) on how to set up the bootstrap daemon.\n\n\n<a name=\"ntox\" />\n###nTox test cli:\n\nnTox is disabled by default. You can enable it by adding --enable-ntox argument to ./configure script like so:\n```bash\n./configure --enable-ntox\n```\nThere is one dependency required for nTox: libncurses.\n\nInstall on fedora:\n```bash\nyum install ncurses-devel\n```\n\nInstall on ubuntu:\n```bash\nsudo apt-get install ncurses-dev\n```\n"
  },
  {
    "path": "Makefile.am",
    "content": "SUBDIRS = build\n\nACLOCAL_AMFLAGS = -I m4\n\npkgconfigdir = $(libdir)/pkgconfig\n\n\npkgconfig_DATA = $(top_builddir)/libtoxcore.pc\nBUILT_SOURCES = $(top_builddir)/libtoxcore.pc\nCLEANFILES = $(top_builddir)/libtoxcore.pc\n\n\nEXTRA_DIST = \\\n\tREADME.md \\\n\tlibtoxcore.pc.in \\\n\ttox.spec \\\n\tdist-build/android-arm.sh \\\n\tdist-build/android-armv7.sh \\\n\tdist-build/android-x86.sh \\\n\tdist-build/android-mips.sh \\\n\tdist-build/android-build.sh \\\n\t$(top_srcdir)/docs/updates/Crypto.md \\\n\t$(top_srcdir)/docs/updates/Spam-Prevention.md \\\n\t$(top_srcdir)/docs/updates/Symmetric-NAT-Transversal.md \\\n\t$(top_srcdir)/other/astyle/README.md \\\n\t$(top_srcdir)/other/astyle/astylerc \\\n\t$(top_srcdir)/other/astyle/pre-commit\n\nif BUILD_AV\n\npkgconfig_DATA += $(top_builddir)/libtoxav.pc\nBUILT_SOURCES += $(top_builddir)/libtoxav.pc\nCLEANFILES += $(top_builddir)/libtoxav.pc\n\nEXTRA_DIST += libtoxav.pc.in\n\nendif\n"
  },
  {
    "path": "README.md",
    "content": "![Project Tox](https://raw.github.com/irungentoo/toxcore/master/other/tox.png \"Project Tox\")\n***\n\nWith the rise of government surveillance programs, Tox, a FOSS initiative, aims to be an easy to use, all-in-one communication platform that ensures full privacy and secure message delivery.<br /> <br />\n\n[**Website**](https://tox.chat) **|** [**Wiki**](https://wiki.tox.chat/) **|** [**Blog**](https://blog.tox.chat/) **|** [**FAQ**](https://wiki.tox.chat/doku.php?id=users:faq) **|** [**Binaries/Downloads**](https://wiki.tox.chat/Binaries) **|** [**Clients**](https://wiki.tox.chat/doku.php?id=clients) **|** [**Compiling**](/INSTALL.md)\n\n**IRC Channels:** [#tox@freenode](https://webchat.freenode.net/?channels=tox), [#tox-dev@freenode](https://webchat.freenode.net/?channels=tox-dev)\n\n\n## The Complex Stuff:\n### UDP vs. TCP\nTox must use UDP simply because [hole punching](https://en.wikipedia.org/wiki/UDP_hole_punching) with TCP is not as reliable.\nHowever, Tox does use [TCP relays](/docs/TCP_Network.txt) as a fallback if it encounters a firewall that prevents UDP hole punching.\n\n### Connecting & Communicating\nEvery peer is represented as a [byte string](https://en.wikipedia.org/wiki/String_(computer_science)) (the public key [Tox ID] of the peer). By using torrent-style DHT, peers can find the IP of other peers by using their Tox ID. Once the IP is obtained, peers can initiate a [secure](/docs/updates/Crypto.md) connection with each other. Once the connection is made, peers can exchange messages, send files, start video chats, etc. using encrypted communications.\n\n\n**Current build status:** [![Build Status](https://travis-ci.org/irungentoo/toxcore.png?branch=master)](https://travis-ci.org/irungentoo/toxcore)\n\n\n## Q&A:\n\n### What are your goals with Tox?\n\nWe want Tox to be as simple as possible while remaining as secure as possible.\n\n### Why are you doing this? There are already a bunch of free Skype alternatives.\nThe 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.\n\n## TODO:\n- [TODO](/docs/TODO.md)\n\n\n## Documentation:\n\n- [Compiling](/INSTALL.md)\n- [DHT Protocol](/docs/updates/DHT.md)<br />\n- [Crypto](/docs/updates/Crypto.md)<br />\n"
  },
  {
    "path": "auto_tests/Makefile.inc",
    "content": "if BUILD_TESTS\n\nTESTS = encryptsave_test messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest\ncheck_PROGRAMS = encryptsave_test messenger_autotest crypto_test network_test assoc_test onion_test TCP_test tox_test dht_autotest\n\nAUTOTEST_CFLAGS = \\\n                         $(LIBSODIUM_CFLAGS) \\\n                         $(NACL_CFLAGS) \\\n                         $(CHECK_CFLAGS)\n\nAUTOTEST_LDADD = \\\n                        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        libtoxencryptsave.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        $(CHECK_LIBS)\n\n\n\nif BUILD_AV\nTESTS += toxav_basic_test toxav_many_test\ncheck_PROGRAMS += toxav_basic_test toxav_many_test\nAUTOTEST_LDADD += libtoxav.la\nendif\n\nmessenger_autotest_SOURCES = ../auto_tests/messenger_test.c\n\nmessenger_autotest_CFLAGS = $(AUTOTEST_CFLAGS)\n\nmessenger_autotest_LDADD = $(AUTOTEST_LDADD)\n\n\ncrypto_test_SOURCES = ../auto_tests/crypto_test.c\n\ncrypto_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\ncrypto_test_LDADD = $(AUTOTEST_LDADD)\n\n\nnetwork_test_SOURCES = ../auto_tests/network_test.c\n\nnetwork_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\nnetwork_test_LDADD = $(AUTOTEST_LDADD)\n\n\nassoc_test_SOURCES = ../auto_tests/assoc_test.c\n\nassoc_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\nassoc_test_LDADD = $(AUTOTEST_LDADD)\n\n\nonion_test_SOURCES = ../auto_tests/onion_test.c\n\nonion_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\nonion_test_LDADD = $(AUTOTEST_LDADD)\n\n\nTCP_test_SOURCES = ../auto_tests/TCP_test.c\n\nTCP_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\nTCP_test_LDADD = $(AUTOTEST_LDADD)\n\n\ntox_test_SOURCES = ../auto_tests/tox_test.c\n\ntox_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\ntox_test_LDADD = $(AUTOTEST_LDADD)\n\n\ndht_autotest_SOURCES = ../auto_tests/dht_test.c\n\ndht_autotest_CFLAGS = $(AUTOTEST_CFLAGS)\n\ndht_autotest_LDADD = $(AUTOTEST_LDADD)\n\n\nif BUILD_AV\ntoxav_basic_test_SOURCES = ../auto_tests/toxav_basic_test.c\n\ntoxav_basic_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\ntoxav_basic_test_LDADD = $(AUTOTEST_LDADD) $(AV_LIBS)\n\n\ntoxav_many_test_SOURCES = ../auto_tests/toxav_many_test.c\n\ntoxav_many_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\ntoxav_many_test_LDADD = $(AUTOTEST_LDADD)\nendif\n\nendif\n\n\nencryptsave_test_SOURCES = ../auto_tests/encryptsave_test.c\n\nencryptsave_test_CFLAGS = $(AUTOTEST_CFLAGS)\n\nencryptsave_test_LDADD = $(AUTOTEST_LDADD)\n\n\nEXTRA_DIST += $(top_srcdir)/auto_tests/friends_test.c \\\n              $(top_srcdir)/auto_tests/helpers.h\n"
  },
  {
    "path": "auto_tests/TCP_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"../toxcore/TCP_server.h\"\n#include \"../toxcore/TCP_client.h\"\n\n#include \"../toxcore/util.h\"\n\n#include \"helpers.h\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n#define NUM_PORTS 3\n\nuint16_t ports[NUM_PORTS] = {1234, 33445, 25643};\n\nSTART_TEST(test_basic)\n{\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_secret_key, NULL);\n    ck_assert_msg(tcp_s != NULL, \"Failed to create TCP relay server\");\n    ck_assert_msg(tcp_s->num_listening_socks == NUM_PORTS, \"Failed to bind to all ports\");\n\n    sock_t sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n    struct sockaddr_in6 addr6_loopback = {0};\n    addr6_loopback.sin6_family = AF_INET6;\n    addr6_loopback.sin6_port = htons(ports[rand() % NUM_PORTS]);\n    addr6_loopback.sin6_addr = in6addr_loopback;\n\n    int ret = connect(sock, (struct sockaddr *)&addr6_loopback, sizeof(addr6_loopback));\n    ck_assert_msg(ret == 0, \"Failed to connect to TCP relay server\");\n\n    uint8_t f_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t f_secret_key[crypto_box_SECRETKEYBYTES];\n    uint8_t f_nonce[crypto_box_NONCEBYTES];\n    crypto_box_keypair(f_public_key, f_secret_key);\n    random_nonce(f_nonce);\n\n    uint8_t t_secret_key[crypto_box_SECRETKEYBYTES];\n    uint8_t handshake_plain[TCP_HANDSHAKE_PLAIN_SIZE];\n    crypto_box_keypair(handshake_plain, t_secret_key);\n    memcpy(handshake_plain + crypto_box_PUBLICKEYBYTES, f_nonce, crypto_box_NONCEBYTES);\n    uint8_t handshake[TCP_CLIENT_HANDSHAKE_SIZE];\n    memcpy(handshake, f_public_key, crypto_box_PUBLICKEYBYTES);\n    new_nonce(handshake + crypto_box_PUBLICKEYBYTES);\n\n    ret = encrypt_data(self_public_key, f_secret_key, handshake + crypto_box_PUBLICKEYBYTES, handshake_plain,\n                       TCP_HANDSHAKE_PLAIN_SIZE, handshake + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);\n    ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES),\n                  \"Encrypt failed.\");\n    ck_assert_msg(send(sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, 0) == TCP_CLIENT_HANDSHAKE_SIZE - 1, \"send Failed.\");\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    ck_assert_msg(send(sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, 0) == 1, \"send Failed.\");\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];\n    uint8_t response_plain[TCP_HANDSHAKE_PLAIN_SIZE];\n    ck_assert_msg(recv(sock, response, TCP_SERVER_HANDSHAKE_SIZE, 0) == TCP_SERVER_HANDSHAKE_SIZE, \"recv Failed.\");\n    ret = decrypt_data(self_public_key, f_secret_key, response, response + crypto_box_NONCEBYTES,\n                       TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, response_plain);\n    ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, \"Decrypt Failed.\");\n    uint8_t f_nonce_r[crypto_box_NONCEBYTES];\n    uint8_t f_shared_key[crypto_box_BEFORENMBYTES];\n    encrypt_precompute(response_plain, t_secret_key, f_shared_key);\n    memcpy(f_nonce_r, response_plain + crypto_box_BEFORENMBYTES, crypto_box_NONCEBYTES);\n\n    uint8_t r_req_p[1 + crypto_box_PUBLICKEYBYTES] = {0};\n    memcpy(r_req_p + 1, f_public_key, crypto_box_PUBLICKEYBYTES);\n    uint8_t r_req[2 + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES];\n    uint16_t size = 1 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES;\n    size = htons(size);\n    ret = encrypt_data_symmetric(f_shared_key, f_nonce, r_req_p, 1 + crypto_box_PUBLICKEYBYTES, r_req + 2);\n    increment_nonce(f_nonce);\n    memcpy(r_req, &size, 2);\n    uint32_t i;\n\n    for (i = 0; i < sizeof(r_req); ++i) {\n        ck_assert_msg(send(sock, r_req + i, 1, 0) == 1, \"send Failed.\");\n        //ck_assert_msg(send(sock, r_req, sizeof(r_req), 0) == sizeof(r_req), \"send Failed.\");\n        do_TCP_server(tcp_s);\n        c_sleep(50);\n    }\n\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    uint8_t packet_resp[4096];\n    int recv_data_len;\n    ck_assert_msg((recv_data_len = recv(sock, packet_resp, 2 + 2 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES,\n                                        0)) == 2 + 2 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES, \"recv Failed. %u\", recv_data_len);\n    memcpy(&size, packet_resp, 2);\n    ck_assert_msg(ntohs(size) == 2 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES, \"Wrong packet size.\");\n    uint8_t packet_resp_plain[4096];\n    ret = decrypt_data_symmetric(f_shared_key, f_nonce_r, packet_resp + 2, recv_data_len - 2, packet_resp_plain);\n    ck_assert_msg(ret != -1, \"decryption failed\");\n    increment_nonce(f_nonce_r);\n    ck_assert_msg(packet_resp_plain[0] == 1, \"wrong packet id %u\", packet_resp_plain[0]);\n    ck_assert_msg(packet_resp_plain[1] == 0, \"connection not refused %u\", packet_resp_plain[1]);\n    ck_assert_msg(public_key_cmp(packet_resp_plain + 2, f_public_key) == 0, \"key in packet wrong\");\n    kill_TCP_server(tcp_s);\n}\nEND_TEST\n\nstruct sec_TCP_con {\n    sock_t  sock;\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t recv_nonce[crypto_box_NONCEBYTES];\n    uint8_t sent_nonce[crypto_box_NONCEBYTES];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n};\n\nstruct sec_TCP_con *new_TCP_con(TCP_Server *tcp_s)\n{\n    struct sec_TCP_con *sec_c = malloc(sizeof(struct sec_TCP_con));\n    sock_t sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);\n    struct sockaddr_in6 addr6_loopback = {0};\n    addr6_loopback.sin6_family = AF_INET6;\n    addr6_loopback.sin6_port = htons(ports[rand() % NUM_PORTS]);\n    addr6_loopback.sin6_addr = in6addr_loopback;\n\n    int ret = connect(sock, (struct sockaddr *)&addr6_loopback, sizeof(addr6_loopback));\n    ck_assert_msg(ret == 0, \"Failed to connect to TCP relay server\");\n\n    uint8_t f_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(sec_c->public_key, f_secret_key);\n    random_nonce(sec_c->sent_nonce);\n\n    uint8_t t_secret_key[crypto_box_SECRETKEYBYTES];\n    uint8_t handshake_plain[TCP_HANDSHAKE_PLAIN_SIZE];\n    crypto_box_keypair(handshake_plain, t_secret_key);\n    memcpy(handshake_plain + crypto_box_PUBLICKEYBYTES, sec_c->sent_nonce, crypto_box_NONCEBYTES);\n    uint8_t handshake[TCP_CLIENT_HANDSHAKE_SIZE];\n    memcpy(handshake, sec_c->public_key, crypto_box_PUBLICKEYBYTES);\n    new_nonce(handshake + crypto_box_PUBLICKEYBYTES);\n\n    ret = encrypt_data(tcp_s->public_key, f_secret_key, handshake + crypto_box_PUBLICKEYBYTES, handshake_plain,\n                       TCP_HANDSHAKE_PLAIN_SIZE, handshake + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);\n    ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES),\n                  \"Encrypt failed.\");\n    ck_assert_msg(send(sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, 0) == TCP_CLIENT_HANDSHAKE_SIZE - 1, \"send Failed.\");\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    ck_assert_msg(send(sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, 0) == 1, \"send Failed.\");\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];\n    uint8_t response_plain[TCP_HANDSHAKE_PLAIN_SIZE];\n    ck_assert_msg(recv(sock, response, TCP_SERVER_HANDSHAKE_SIZE, 0) == TCP_SERVER_HANDSHAKE_SIZE, \"recv Failed.\");\n    ret = decrypt_data(tcp_s->public_key, f_secret_key, response, response + crypto_box_NONCEBYTES,\n                       TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, response_plain);\n    ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, \"Decrypt Failed.\");\n    encrypt_precompute(response_plain, t_secret_key, sec_c->shared_key);\n    memcpy(sec_c->recv_nonce, response_plain + crypto_box_BEFORENMBYTES, crypto_box_NONCEBYTES);\n    sec_c->sock = sock;\n    return sec_c;\n}\n\nvoid kill_TCP_con(struct sec_TCP_con *con)\n{\n    kill_sock(con->sock);\n    free(con);\n}\n\nint write_packet_TCP_secure_connection(struct sec_TCP_con *con, uint8_t *data, uint16_t length)\n{\n    uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES];\n\n    uint16_t c_length = htons(length + crypto_box_MACBYTES);\n    memcpy(packet, &c_length, sizeof(uint16_t));\n    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));\n\n    if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))\n        return -1;\n\n    increment_nonce(con->sent_nonce);\n\n    ck_assert_msg(send(con->sock, packet, sizeof(packet), 0) == sizeof(packet), \"send failed\");\n    return 0;\n}\n\nint read_packet_sec_TCP(struct sec_TCP_con *con, uint8_t *data, uint16_t length)\n{\n    int len;\n    ck_assert_msg((len = recv(con->sock, data, length, 0)) == length, \"wrong len %i\\n\", len);\n    ck_assert_msg((len = decrypt_data_symmetric(con->shared_key, con->recv_nonce, data + 2, length - 2, data)) != -1,\n                  \"Decrypt failed\");\n    increment_nonce(con->recv_nonce);\n    return len;\n}\n\nSTART_TEST(test_some)\n{\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_secret_key, NULL);\n    ck_assert_msg(tcp_s != NULL, \"Failed to create TCP relay server\");\n    ck_assert_msg(tcp_s->num_listening_socks == NUM_PORTS, \"Failed to bind to all ports\");\n\n    struct sec_TCP_con *con1 = new_TCP_con(tcp_s);\n    struct sec_TCP_con *con2 = new_TCP_con(tcp_s);\n    struct sec_TCP_con *con3 = new_TCP_con(tcp_s);\n\n    uint8_t requ_p[1 + crypto_box_PUBLICKEYBYTES];\n    requ_p[0] = 0;\n    memcpy(requ_p + 1, con3->public_key, crypto_box_PUBLICKEYBYTES);\n    write_packet_TCP_secure_connection(con1, requ_p, sizeof(requ_p));\n    memcpy(requ_p + 1, con1->public_key, crypto_box_PUBLICKEYBYTES);\n    write_packet_TCP_secure_connection(con3, requ_p, sizeof(requ_p));\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    uint8_t data[2048];\n    int len = read_packet_sec_TCP(con1, data, 2 + 1 + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES);\n    ck_assert_msg(len == 1 + 1 + crypto_box_PUBLICKEYBYTES, \"wrong len %u\", len);\n    ck_assert_msg(data[0] == 1, \"wrong packet id %u\", data[0]);\n    ck_assert_msg(data[1] == 16, \"connection not refused %u\", data[1]);\n    ck_assert_msg(public_key_cmp(data + 2, con3->public_key) == 0, \"key in packet wrong\");\n    len = read_packet_sec_TCP(con3, data, 2 + 1 + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES);\n    ck_assert_msg(len == 1 + 1 + crypto_box_PUBLICKEYBYTES, \"wrong len %u\", len);\n    ck_assert_msg(data[0] == 1, \"wrong packet id %u\", data[0]);\n    ck_assert_msg(data[1] == 16, \"connection not refused %u\", data[1]);\n    ck_assert_msg(public_key_cmp(data + 2, con1->public_key) == 0, \"key in packet wrong\");\n\n    uint8_t test_packet[512] = {16, 17, 16, 86, 99, 127, 255, 189, 78};\n    write_packet_TCP_secure_connection(con3, test_packet, sizeof(test_packet));\n    write_packet_TCP_secure_connection(con3, test_packet, sizeof(test_packet));\n    write_packet_TCP_secure_connection(con3, test_packet, sizeof(test_packet));\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    len = read_packet_sec_TCP(con1, data, 2 + 2 + crypto_box_MACBYTES);\n    ck_assert_msg(len == 2, \"wrong len %u\", len);\n    ck_assert_msg(data[0] == 2, \"wrong packet id %u\", data[0]);\n    ck_assert_msg(data[1] == 16, \"wrong peer id %u\", data[1]);\n    len = read_packet_sec_TCP(con3, data, 2 + 2 + crypto_box_MACBYTES);\n    ck_assert_msg(len == 2, \"wrong len %u\", len);\n    ck_assert_msg(data[0] == 2, \"wrong packet id %u\", data[0]);\n    ck_assert_msg(data[1] == 16, \"wrong peer id %u\", data[1]);\n    len = read_packet_sec_TCP(con1, data, 2 + sizeof(test_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(test_packet), \"wrong len %u\", len);\n    ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, \"packet is wrong %u %u %u %u\", data[0], data[1],\n                  data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]);\n    len = read_packet_sec_TCP(con1, data, 2 + sizeof(test_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(test_packet), \"wrong len %u\", len);\n    ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, \"packet is wrong %u %u %u %u\", data[0], data[1],\n                  data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]);\n    len = read_packet_sec_TCP(con1, data, 2 + sizeof(test_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(test_packet), \"wrong len %u\", len);\n    ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, \"packet is wrong %u %u %u %u\", data[0], data[1],\n                  data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]);\n    write_packet_TCP_secure_connection(con1, test_packet, sizeof(test_packet));\n    write_packet_TCP_secure_connection(con1, test_packet, sizeof(test_packet));\n    write_packet_TCP_secure_connection(con1, test_packet, sizeof(test_packet));\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    len = read_packet_sec_TCP(con3, data, 2 + sizeof(test_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(test_packet), \"wrong len %u\", len);\n    ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, \"packet is wrong %u %u %u %u\", data[0], data[1],\n                  data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]);\n    len = read_packet_sec_TCP(con3, data, 2 + sizeof(test_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(test_packet), \"wrong len %u\", len);\n    ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, \"packet is wrong %u %u %u %u\", data[0], data[1],\n                  data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]);\n    len = read_packet_sec_TCP(con3, data, 2 + sizeof(test_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(test_packet), \"wrong len %u\", len);\n    ck_assert_msg(memcmp(data, test_packet, sizeof(test_packet)) == 0, \"packet is wrong %u %u %u %u\", data[0], data[1],\n                  data[sizeof(test_packet) - 2], data[sizeof(test_packet) - 1]);\n\n    uint8_t ping_packet[1 + sizeof(uint64_t)] = {4, 8, 6, 9, 67};\n    write_packet_TCP_secure_connection(con1, ping_packet, sizeof(ping_packet));\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    len = read_packet_sec_TCP(con1, data, 2 + sizeof(ping_packet) + crypto_box_MACBYTES);\n    ck_assert_msg(len == sizeof(ping_packet), \"wrong len %u\", len);\n    ck_assert_msg(data[0] == 5, \"wrong packet id %u\", data[0]);\n    ck_assert_msg(memcmp(ping_packet + 1, data + 1, sizeof(uint64_t)) == 0, \"wrong packet data\");\n    kill_TCP_server(tcp_s);\n    kill_TCP_con(con1);\n    kill_TCP_con(con2);\n    kill_TCP_con(con3);\n}\nEND_TEST\n\nstatic int response_callback_good;\nstatic uint8_t response_callback_connection_id;\nstatic uint8_t response_callback_public_key[crypto_box_PUBLICKEYBYTES];\nstatic int response_callback(void *object, uint8_t connection_id, const uint8_t *public_key)\n{\n    if (set_tcp_connection_number(object - 2, connection_id, 7) != 0)\n        return 1;\n\n    response_callback_connection_id = connection_id;\n    memcpy(response_callback_public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    response_callback_good++;\n    return 0;\n}\nstatic int status_callback_good;\nstatic uint8_t status_callback_connection_id;\nstatic uint8_t status_callback_status;\nstatic int status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status)\n{\n    if (object != (void *)2)\n        return 1;\n\n    if (number != 7)\n        return 1;\n\n    status_callback_connection_id = connection_id;\n    status_callback_status = status;\n    status_callback_good++;\n    return 0;\n}\nstatic int data_callback_good;\nstatic int data_callback(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length)\n{\n    if (object != (void *)3)\n        return 1;\n\n    if (number != 7)\n        return 1;\n\n    if (length != 5)\n        return 1;\n\n    if (data[0] == 1 && data[1] == 2 && data[2] == 3 && data[3] == 4 && data[4] == 5) {\n        data_callback_good++;\n        return 0;\n    }\n\n    return 1;\n}\n\nstatic int oob_data_callback_good;\nstatic uint8_t oob_pubkey[crypto_box_PUBLICKEYBYTES];\nstatic int oob_data_callback(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length)\n{\n    if (object != (void *)4)\n        return 1;\n\n    if (length != 5)\n        return 1;\n\n    if (public_key_cmp(public_key, oob_pubkey) != 0)\n        return 1;\n\n    if (data[0] == 1 && data[1] == 2 && data[2] == 3 && data[3] == 4 && data[4] == 5) {\n        oob_data_callback_good++;\n        return 0;\n    }\n\n    return 1;\n}\n\nSTART_TEST(test_client)\n{\n    unix_time_update();\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_secret_key, NULL);\n    ck_assert_msg(tcp_s != NULL, \"Failed to create TCP relay server\");\n    ck_assert_msg(tcp_s->num_listening_socks == NUM_PORTS, \"Failed to bind to all ports\");\n\n    uint8_t f_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t f_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(f_public_key, f_secret_key);\n    IP_Port ip_port_tcp_s;\n\n    ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);\n    ip_port_tcp_s.ip.family = AF_INET6;\n    ip_port_tcp_s.ip.ip6.in6_addr = in6addr_loopback;\n    TCP_Client_Connection *conn = new_TCP_connection(ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, 0);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_UNCONFIRMED, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_UNCONFIRMED,\n                  conn->status);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_CONFIRMED,\n                  conn->status);\n    c_sleep(500);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_CONFIRMED,\n                  conn->status);\n    c_sleep(500);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_CONFIRMED,\n                  conn->status);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_CONFIRMED,\n                  conn->status);\n\n    uint8_t f2_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t f2_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(f2_public_key, f2_secret_key);\n    ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);\n    TCP_Client_Connection *conn2 = new_TCP_connection(ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key, 0);\n    routing_response_handler(conn, response_callback, ((void *)conn) + 2);\n    routing_status_handler(conn, status_callback, (void *)2);\n    routing_data_handler(conn, data_callback, (void *)3);\n    oob_data_handler(conn, oob_data_callback, (void *)4);\n    oob_data_callback_good = response_callback_good = status_callback_good = data_callback_good = 0;\n    c_sleep(50);\n    do_TCP_connection(conn);\n    do_TCP_connection(conn2);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    do_TCP_connection(conn2);\n    c_sleep(50);\n    uint8_t data[5] = {1, 2, 3, 4, 5};\n    memcpy(oob_pubkey, f2_public_key, crypto_box_PUBLICKEYBYTES);\n    send_oob_packet(conn2, f_public_key, data, 5);\n    send_routing_request(conn, f2_public_key);\n    send_routing_request(conn2, f_public_key);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    do_TCP_connection(conn2);\n    ck_assert_msg(oob_data_callback_good == 1, \"oob callback not called\");\n    ck_assert_msg(response_callback_good == 1, \"response callback not called\");\n    ck_assert_msg(public_key_cmp(response_callback_public_key, f2_public_key) == 0, \"wrong public key\");\n    ck_assert_msg(status_callback_good == 1, \"status callback not called\");\n    ck_assert_msg(status_callback_status == 2, \"wrong status\");\n    ck_assert_msg(status_callback_connection_id == response_callback_connection_id, \"connection ids not equal\");\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    ck_assert_msg(send_data(conn2, 0, data, 5) == 1, \"send data failed\");\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    do_TCP_connection(conn2);\n    ck_assert_msg(data_callback_good == 1, \"data callback not called\");\n    status_callback_good = 0;\n    send_disconnect_request(conn2, 0);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    do_TCP_connection(conn2);\n    ck_assert_msg(status_callback_good == 1, \"status callback not called\");\n    ck_assert_msg(status_callback_status == 1, \"wrong status\");\n    kill_TCP_server(tcp_s);\n    kill_TCP_connection(conn);\n    kill_TCP_connection(conn2);\n}\nEND_TEST\n\nSTART_TEST(test_client_invalid)\n{\n    unix_time_update();\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(self_public_key, self_secret_key);\n\n    uint8_t f_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t f_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(f_public_key, f_secret_key);\n    IP_Port ip_port_tcp_s;\n\n    ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);\n    ip_port_tcp_s.ip.family = AF_INET6;\n    ip_port_tcp_s.ip.ip6.in6_addr = in6addr_loopback;\n    TCP_Client_Connection *conn = new_TCP_connection(ip_port_tcp_s, self_public_key, f_public_key, f_secret_key, 0);\n    c_sleep(50);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_CONNECTING, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_CONNECTING,\n                  conn->status);\n    c_sleep(5000);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_CONNECTING, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_CONNECTING,\n                  conn->status);\n    c_sleep(6000);\n    do_TCP_connection(conn);\n    ck_assert_msg(conn->status == TCP_CLIENT_DISCONNECTED, \"Wrong status. Expected: %u, is: %u\", TCP_CLIENT_DISCONNECTED,\n                  conn->status);\n\n    kill_TCP_connection(conn);\n}\nEND_TEST\n\n#include \"../toxcore/TCP_connection.h\"\n\n_Bool tcp_data_callback_called;\nstatic int tcp_data_callback(void *object, int id, const uint8_t *data, uint16_t length)\n{\n    if (object != (void *)120397)\n        return -1;\n\n    if (id != 123)\n        return -1;\n\n    if (length != 6)\n        return -1;\n\n    if (memcmp(data, \"Gentoo\", length) != 0)\n        return -1;\n\n    tcp_data_callback_called = 1;\n    return 0;\n}\n\n\nSTART_TEST(test_tcp_connection)\n{\n    tcp_data_callback_called = 0;\n    unix_time_update();\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_secret_key, NULL);\n    ck_assert_msg(public_key_cmp(tcp_s->public_key, self_public_key) == 0, \"Wrong public key\");\n\n    TCP_Proxy_Info proxy_info;\n    proxy_info.proxy_type = TCP_PROXY_NONE;\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Connections *tc_1 = new_tcp_connections(self_secret_key, &proxy_info);\n    ck_assert_msg(public_key_cmp(tc_1->self_public_key, self_public_key) == 0, \"Wrong public key\");\n\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Connections *tc_2 = new_tcp_connections(self_secret_key, &proxy_info);\n    ck_assert_msg(public_key_cmp(tc_2->self_public_key, self_public_key) == 0, \"Wrong public key\");\n\n    IP_Port ip_port_tcp_s;\n\n    ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);\n    ip_port_tcp_s.ip.family = AF_INET6;\n    ip_port_tcp_s.ip.ip6.in6_addr = in6addr_loopback;\n\n    int connection = new_tcp_connection_to(tc_1, tc_2->self_public_key, 123);\n    ck_assert_msg(connection == 0, \"Connection id wrong\");\n    ck_assert_msg(add_tcp_relay_connection(tc_1, connection, ip_port_tcp_s, tcp_s->public_key) == 0,\n                  \"Could not add tcp relay to connection\\n\");\n\n    ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);\n    connection = new_tcp_connection_to(tc_2, tc_1->self_public_key, 123);\n    ck_assert_msg(connection == 0, \"Connection id wrong\");\n    ck_assert_msg(add_tcp_relay_connection(tc_2, connection, ip_port_tcp_s, tcp_s->public_key) == 0,\n                  \"Could not add tcp relay to connection\\n\");\n\n    ck_assert_msg(new_tcp_connection_to(tc_2, tc_1->self_public_key, 123) == -1, \"Managed to readd same connection\\n\");\n\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n\n    int ret = send_packet_tcp_connection(tc_1, 0, \"Gentoo\", 6);\n    ck_assert_msg(ret == 0, \"could not send packet.\");\n    set_packet_tcp_connection_callback(tc_2, &tcp_data_callback, (void *) 120397);\n\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n\n    ck_assert_msg(tcp_data_callback_called, \"could not recv packet.\");\n    ck_assert_msg(tcp_connection_to_online_tcp_relays(tc_1, 0) == 1, \"Wrong number of connected relays\");\n    ck_assert_msg(kill_tcp_connection_to(tc_1, 0) == 0, \"could not kill connection to\\n\");\n\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n\n    ck_assert_msg(send_packet_tcp_connection(tc_1, 0, \"Gentoo\", 6) == -1, \"could send packet.\");\n    ck_assert_msg(kill_tcp_connection_to(tc_2, 0) == 0, \"could not kill connection to\\n\");\n\n    kill_TCP_server(tcp_s);\n    kill_tcp_connections(tc_1);\n    kill_tcp_connections(tc_2);\n}\nEND_TEST\n\n_Bool tcp_oobdata_callback_called;\nstatic int tcp_oobdata_callback(void *object, const uint8_t *public_key, unsigned int id, const uint8_t *data,\n                                uint16_t length)\n{\n    if (length != 6)\n        return -1;\n\n    if (memcmp(data, \"Gentoo\", length) != 0)\n        return -1;\n\n    if (tcp_send_oob_packet(object, id, public_key, data, length) == 0)\n        tcp_oobdata_callback_called = 1;\n\n    return 0;\n}\n\nSTART_TEST(test_tcp_connection2)\n{\n    tcp_oobdata_callback_called = 0;\n    tcp_data_callback_called = 0;\n\n    unix_time_update();\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_secret_key, NULL);\n    ck_assert_msg(public_key_cmp(tcp_s->public_key, self_public_key) == 0, \"Wrong public key\");\n\n    TCP_Proxy_Info proxy_info;\n    proxy_info.proxy_type = TCP_PROXY_NONE;\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Connections *tc_1 = new_tcp_connections(self_secret_key, &proxy_info);\n    ck_assert_msg(public_key_cmp(tc_1->self_public_key, self_public_key) == 0, \"Wrong public key\");\n\n    crypto_box_keypair(self_public_key, self_secret_key);\n    TCP_Connections *tc_2 = new_tcp_connections(self_secret_key, &proxy_info);\n    ck_assert_msg(public_key_cmp(tc_2->self_public_key, self_public_key) == 0, \"Wrong public key\");\n\n    IP_Port ip_port_tcp_s;\n\n    ip_port_tcp_s.port = htons(ports[rand() % NUM_PORTS]);\n    ip_port_tcp_s.ip.family = AF_INET6;\n    ip_port_tcp_s.ip.ip6.in6_addr = in6addr_loopback;\n\n    int connection = new_tcp_connection_to(tc_1, tc_2->self_public_key, 123);\n    ck_assert_msg(connection == 0, \"Connection id wrong\");\n    ck_assert_msg(add_tcp_relay_connection(tc_1, connection, ip_port_tcp_s, tcp_s->public_key) == 0,\n                  \"Could not add tcp relay to connection\\n\");\n\n    ck_assert_msg(add_tcp_relay_global(tc_2, ip_port_tcp_s, tcp_s->public_key) == 0, \"Could not add global relay\");\n\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n\n    int ret = send_packet_tcp_connection(tc_1, 0, \"Gentoo\", 6);\n    ck_assert_msg(ret == 0, \"could not send packet.\");\n    set_oob_packet_tcp_connection_callback(tc_2, &tcp_oobdata_callback, tc_2);\n    set_packet_tcp_connection_callback(tc_1, &tcp_data_callback, (void *) 120397);\n\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n\n    ck_assert_msg(tcp_oobdata_callback_called, \"could not recv packet.\");\n\n    c_sleep(50);\n    do_TCP_server(tcp_s);\n    c_sleep(50);\n\n    do_tcp_connections(tc_1);\n    do_tcp_connections(tc_2);\n\n    ck_assert_msg(tcp_data_callback_called, \"could not recv packet.\");\n    ck_assert_msg(kill_tcp_connection_to(tc_1, 0) == 0, \"could not kill connection to\\n\");\n\n    kill_TCP_server(tcp_s);\n    kill_tcp_connections(tc_1);\n    kill_tcp_connections(tc_2);\n}\nEND_TEST\n\nSuite *TCP_suite(void)\n{\n    Suite *s = suite_create(\"TCP\");\n\n    DEFTESTCASE_SLOW(basic, 5);\n    DEFTESTCASE_SLOW(some, 10);\n    DEFTESTCASE_SLOW(client, 10);\n    DEFTESTCASE_SLOW(client_invalid, 15);\n    DEFTESTCASE_SLOW(tcp_connection, 20);\n    DEFTESTCASE_SLOW(tcp_connection2, 20);\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *TCP = TCP_suite();\n    SRunner *test_runner = srunner_create(TCP);\n\n    int number_failed = 0;\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/assoc_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#define AUTO_TEST\n#include \"../toxcore/DHT.h\"\n#include \"../toxcore/assoc.h\"\n#include \"../toxcore/util.h\"\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n\n#include <check.h>\n\n#include \"helpers.h\"\n\nSTART_TEST(test_basics)\n{\n    /* TODO: real test */\n    uint8_t id[crypto_box_PUBLICKEYBYTES];\n    Assoc *assoc = new_Assoc_default(id);\n    ck_assert_msg(assoc != NULL, \"failed to create default assoc\");\n\n    kill_Assoc(assoc);\n    assoc = new_Assoc(17, 4, id); /* results in an assoc of 16/3 */\n    ck_assert_msg(assoc != NULL, \"failed to create customized assoc\");\n\n    IP_Port ipp;\n    ipp.ip.family = AF_INET;\n    ipp.ip.ip4.uint8[0] = 1;\n    ipp.port = htons(12345);\n\n    IPPTs ippts_send;\n    ippts_send.ip_port = ipp;\n    ippts_send.timestamp = unix_time();\n    IP_Port ipp_recv = ipp;\n\n    uint8_t res = Assoc_add_entry(assoc, id, &ippts_send, &ipp_recv, 0);\n    ck_assert_msg(res == 0, \"stored self as entry: expected %u, got %u\", 0, res);\n\n    id[0]++;\n\n    res = Assoc_add_entry(assoc, id, &ippts_send, &ipp_recv, 0);\n    ck_assert_msg(res == 1, \"failed to store entry: expected %u, got %u\", 1, res);\n\n    Assoc_close_entries close_entries;\n    memset(&close_entries, 0, sizeof(close_entries));\n    close_entries.count = 4;\n    close_entries.count_good = 2;\n    close_entries.wanted_id = id;\n\n    Client_data *entries[close_entries.count];\n    close_entries.result = entries;\n\n    uint8_t found = Assoc_get_close_entries(assoc, &close_entries);\n    ck_assert_msg(found == 1, \"get_close_entries(): expected %u, got %u\", 1, found);\n    kill_Assoc(assoc);\n}\nEND_TEST\n\nSTART_TEST(test_fillup)\n{\n    /* TODO: real test */\n    int i, j;\n    uint8_t id[crypto_box_PUBLICKEYBYTES];\n    //uint32_t a = current_time();\n    uint32_t a = 2710106197;\n    srand(a);\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {\n        id[i] = rand();\n    }\n\n    Assoc *assoc = new_Assoc(6, 15, id);\n    ck_assert_msg(assoc != NULL, \"failed to create default assoc\");\n    struct entry {\n        uint8_t id[crypto_box_PUBLICKEYBYTES];\n        IPPTs ippts_send;\n        IP_Port ipp_recv;\n    };\n    unsigned int fail = 0;\n    struct entry entries[128];\n    struct entry closest[8];\n\n    for (j = 0; j < 128; ++j) {\n\n        for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {\n            entries[j].id[i] = rand();\n        }\n\n        IP_Port ipp;\n        ipp.ip.family = AF_INET;\n        ipp.ip.ip4.uint32 = rand();\n        ipp.port = rand();\n        entries[j].ippts_send.ip_port = ipp;\n        entries[j].ippts_send.timestamp = unix_time();\n        ipp.ip.ip4.uint32 = rand();\n        ipp.port = rand();\n        entries[j].ipp_recv = ipp;\n\n        if (j % 16 == 0) {\n            memcpy(entries[j].id, id, crypto_box_PUBLICKEYBYTES - 30);\n            memcpy(&closest[j / 16], &entries[j], sizeof(struct entry));\n\n        }\n\n        uint8_t res = Assoc_add_entry(assoc, entries[j].id, &entries[j].ippts_send, &entries[j].ipp_recv, 1);\n        ck_assert_msg(res == 1, \"failed to store entry: expected %u, got %u, j = %u\", 1, res, j);\n    }\n\n    int good = 0;\n    Assoc_close_entries close_entries;\n    memset(&close_entries, 0, sizeof(close_entries));\n    close_entries.count = 8;\n    close_entries.count_good = 8;\n    close_entries.wanted_id = id;\n\n    Client_data *entri[close_entries.count];\n    close_entries.result = entri;\n\n    uint8_t found = Assoc_get_close_entries(assoc, &close_entries);\n    ck_assert_msg(found == 8, \"get_close_entries(): expected %u, got %u\", 1, found);\n\n    for (i = 0; i < 8; ++i) {\n        for (j = 0; j < 8; ++j) {\n            if (id_equal(entri[j]->public_key, closest[i].id))\n                ++good;\n        }\n    }\n\n    ck_assert_msg(good == 8, \"Entries found were not the closest ones. Only %u/8 were.\", good);\n    //printf(\"good: %u %u %u\\n\", good, a, ((uint32_t)current_time() - a));\n    kill_Assoc(assoc);\n}\nEND_TEST\n\nSuite *Assoc_suite(void)\n{\n    Suite *s = suite_create(\"Assoc\");\n\n    DEFTESTCASE(basics);\n    DEFTESTCASE(fillup);\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    unix_time_update();\n    Suite *Assoc = Assoc_suite();\n    SRunner *test_runner = srunner_create(Assoc);\n\n    srunner_set_fork_status(test_runner, CK_NOFORK);\n\n    srunner_run_all(test_runner, CK_NORMAL);\n\n    int number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/crypto_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/net_crypto.h\"\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"helpers.h\"\n\nvoid rand_bytes(uint8_t *b, size_t blen)\n{\n    size_t i;\n\n    for (i = 0; i < blen; i++) {\n        b[i] = rand();\n    }\n}\n\n// These test vectors are from libsodium's test suite\n\nunsigned char alicesk[32] = {\n    0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d,\n    0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,\n    0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,\n    0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a\n};\n\nunsigned char bobpk[32] = {\n    0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4,\n    0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37,\n    0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d,\n    0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f\n};\n\nunsigned char nonce[24] = {\n    0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73,\n    0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6,\n    0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37\n};\n\nunsigned char test_m[131] = {\n    0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5,\n    0xcf, 0x14, 0x13, 0x16, 0xeb, 0xeb, 0x0c, 0x7b,\n    0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4,\n    0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc,\n    0xe5, 0xec, 0xba, 0xaf, 0x33, 0xbd, 0x75, 0x1a,\n    0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29,\n    0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4,\n    0x1d, 0xb6, 0x6c, 0xce, 0x31, 0x4a, 0xdb, 0x31,\n    0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d,\n    0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57,\n    0xe2, 0xf6, 0x55, 0x6a, 0xd6, 0xb1, 0x31, 0x8a,\n    0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde,\n    0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd,\n    0x49, 0x24, 0xca, 0x1c, 0x60, 0x90, 0x2e, 0x52,\n    0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40,\n    0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64,\n    0x5e, 0x07, 0x05\n};\n\nunsigned char test_c[147] = {\n    0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5,\n    0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33, 0x05, 0xd9,\n    0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73,\n    0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc, 0x76, 0xce,\n    0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4,\n    0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a,\n    0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b,\n    0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72,\n    0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2,\n    0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38,\n    0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a,\n    0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae,\n    0x90, 0x22, 0x43, 0x68, 0x51, 0x7a, 0xcf, 0xea,\n    0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda,\n    0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde,\n    0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3,\n    0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6,\n    0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74,\n    0xe3, 0x55, 0xa5\n};\n\nSTART_TEST(test_known)\n{\n    unsigned char c[147];\n    unsigned char m[131];\n    int clen, mlen;\n\n    ck_assert_msg(sizeof(c) == sizeof(m) + crypto_box_MACBYTES * sizeof(unsigned char),\n                  \"cyphertext should be crypto_box_MACBYTES bytes longer than plaintext\");\n    ck_assert_msg(sizeof(test_c) == sizeof(c), \"sanity check failed\");\n    ck_assert_msg(sizeof(test_m) == sizeof(m), \"sanity check failed\");\n\n    clen = encrypt_data(bobpk, alicesk, nonce, test_m, sizeof(test_m) / sizeof(unsigned char), c);\n\n    ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, \"cyphertext doesn't match test vector\");\n    ck_assert_msg(clen == sizeof(c) / sizeof(unsigned char), \"wrong ciphertext length\");\n\n    mlen = decrypt_data(bobpk, alicesk, nonce, test_c, sizeof(test_c) / sizeof(unsigned char), m);\n\n    ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, \"decrypted text doesn't match test vector\");\n    ck_assert_msg(mlen == sizeof(m) / sizeof(unsigned char), \"wrong plaintext length\");\n}\nEND_TEST\n\nSTART_TEST(test_fast_known)\n{\n    unsigned char k[crypto_box_BEFORENMBYTES];\n    unsigned char c[147];\n    unsigned char m[131];\n    int clen, mlen;\n\n    encrypt_precompute(bobpk, alicesk, k);\n\n    ck_assert_msg(sizeof(c) == sizeof(m) + crypto_box_MACBYTES * sizeof(unsigned char),\n                  \"cyphertext should be crypto_box_MACBYTES bytes longer than plaintext\");\n    ck_assert_msg(sizeof(test_c) == sizeof(c), \"sanity check failed\");\n    ck_assert_msg(sizeof(test_m) == sizeof(m), \"sanity check failed\");\n\n    clen = encrypt_data_symmetric(k, nonce, test_m, sizeof(test_m) / sizeof(unsigned char), c);\n\n    ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, \"cyphertext doesn't match test vector\");\n    ck_assert_msg(clen == sizeof(c) / sizeof(unsigned char), \"wrong ciphertext length\");\n\n    mlen = decrypt_data_symmetric(k, nonce, test_c, sizeof(test_c) / sizeof(unsigned char), m);\n\n    ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, \"decrypted text doesn't match test vector\");\n    ck_assert_msg(mlen == sizeof(m) / sizeof(unsigned char), \"wrong plaintext length\");\n\n}\nEND_TEST\n\nSTART_TEST(test_endtoend)\n{\n    unsigned char pk1[crypto_box_PUBLICKEYBYTES];\n    unsigned char sk1[crypto_box_SECRETKEYBYTES];\n    unsigned char pk2[crypto_box_PUBLICKEYBYTES];\n    unsigned char sk2[crypto_box_SECRETKEYBYTES];\n    unsigned char k1[crypto_box_BEFORENMBYTES];\n    unsigned char k2[crypto_box_BEFORENMBYTES];\n\n    unsigned char n[crypto_box_NONCEBYTES];\n\n    unsigned char m[500];\n    unsigned char c1[sizeof(m) + crypto_box_MACBYTES];\n    unsigned char c2[sizeof(m) + crypto_box_MACBYTES];\n    unsigned char c3[sizeof(m) + crypto_box_MACBYTES];\n    unsigned char c4[sizeof(m) + crypto_box_MACBYTES];\n    unsigned char m1[sizeof(m)];\n    unsigned char m2[sizeof(m)];\n    unsigned char m3[sizeof(m)];\n    unsigned char m4[sizeof(m)];\n\n    int mlen;\n    int c1len, c2len, c3len, c4len;\n    int m1len, m2len, m3len, m4len;\n\n    int testno;\n\n    // Test 100 random messages and keypairs\n    for (testno = 0; testno < 100; testno++) {\n        //Generate random message (random length from 100 to 500)\n        mlen = (rand() % 400) + 100;\n        rand_bytes(m, mlen);\n        rand_bytes(n, crypto_box_NONCEBYTES);\n\n        //Generate keypairs\n        crypto_box_keypair(pk1, sk1);\n        crypto_box_keypair(pk2, sk2);\n\n        //Precompute shared keys\n        encrypt_precompute(pk2, sk1, k1);\n        encrypt_precompute(pk1, sk2, k2);\n\n        ck_assert_msg(memcmp(k1, k2, crypto_box_BEFORENMBYTES) == 0, \"encrypt_precompute: bad\");\n\n        //Encrypt all four ways\n        c1len = encrypt_data(pk2, sk1, n, m, mlen, c1);\n        c2len = encrypt_data(pk1, sk2, n, m, mlen, c2);\n        c3len = encrypt_data_symmetric(k1, n, m, mlen, c3);\n        c4len = encrypt_data_symmetric(k2, n, m, mlen, c4);\n\n        ck_assert_msg(c1len == c2len && c1len == c3len && c1len == c4len, \"cyphertext lengths differ\");\n        ck_assert_msg(c1len == mlen + (int)crypto_box_MACBYTES, \"wrong cyphertext length\");\n        ck_assert_msg(memcmp(c1, c2, c1len) == 0 && memcmp(c1, c3, c1len) == 0\n                      && memcmp(c1, c4, c1len) == 0, \"crypertexts differ\");\n\n        //Decrypt all four ways\n        m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1);\n        m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2);\n        m3len = decrypt_data_symmetric(k1, n, c1, c1len, m3);\n        m4len = decrypt_data_symmetric(k2, n, c1, c1len, m4);\n\n        ck_assert_msg(m1len == m2len && m1len == m3len && m1len == m4len, \"decrypted text lengths differ\");\n        ck_assert_msg(m1len == mlen, \"wrong decrypted text length\");\n        ck_assert_msg(memcmp(m1, m2, mlen) == 0 && memcmp(m1, m3, mlen) == 0\n                      && memcmp(m1, m4, mlen) == 0, \"decrypted texts differ\");\n        ck_assert_msg(memcmp(m1, m, mlen) == 0, \"wrong decrypted text\");\n    }\n}\nEND_TEST\n\nSTART_TEST(test_large_data)\n{\n    unsigned char k[crypto_box_BEFORENMBYTES];\n\n    unsigned char n[crypto_box_NONCEBYTES];\n\n    unsigned char m1[MAX_CRYPTO_PACKET_SIZE - crypto_box_MACBYTES];\n    unsigned char c1[sizeof(m1) + crypto_box_MACBYTES];\n    unsigned char m1prime[sizeof(m1)];\n\n    unsigned char m2[MAX_CRYPTO_PACKET_SIZE];\n    unsigned char c2[sizeof(m2) + crypto_box_MACBYTES];\n\n    int c1len, c2len;\n    int m1plen;\n\n    //Generate random messages\n    rand_bytes(m1, sizeof(m1));\n    rand_bytes(m2, sizeof(m2));\n    rand_bytes(n, crypto_box_NONCEBYTES);\n\n    //Generate key\n    rand_bytes(k, crypto_box_BEFORENMBYTES);\n\n    c1len = encrypt_data_symmetric(k, n, m1, sizeof(m1), c1);\n    c2len = encrypt_data_symmetric(k, n, m2, sizeof(m2), c2);\n\n    ck_assert_msg(c1len == sizeof(m1) + crypto_box_MACBYTES, \"could not encrypt\");\n    ck_assert_msg(c2len == sizeof(m2) + crypto_box_MACBYTES, \"could not encrypt\");\n\n    m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime);\n\n    ck_assert_msg(m1plen == sizeof(m1), \"decrypted text lengths differ\");\n    ck_assert_msg(memcmp(m1prime, m1, sizeof(m1)) == 0, \"decrypted texts differ\");\n}\nEND_TEST\n\nSTART_TEST(test_large_data_symmetric)\n{\n    unsigned char k[crypto_box_KEYBYTES];\n\n    unsigned char n[crypto_box_NONCEBYTES];\n\n    unsigned char m1[16 * 16 * 16];\n    unsigned char c1[sizeof(m1) + crypto_box_MACBYTES];\n    unsigned char m1prime[sizeof(m1)];\n\n    int c1len;\n    int m1plen;\n\n    //Generate random messages\n    rand_bytes(m1, sizeof(m1));\n    rand_bytes(n, crypto_box_NONCEBYTES);\n\n    //Generate key\n    new_symmetric_key(k);\n\n    c1len = encrypt_data_symmetric(k, n, m1, sizeof(m1), c1);\n    ck_assert_msg(c1len == sizeof(m1) + crypto_box_MACBYTES, \"could not encrypt data\");\n\n    m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime);\n\n    ck_assert_msg(m1plen == sizeof(m1), \"decrypted text lengths differ\");\n    ck_assert_msg(memcmp(m1prime, m1, sizeof(m1)) == 0, \"decrypted texts differ\");\n}\nEND_TEST\n\nvoid increment_nonce_number_cmp(uint8_t *nonce, uint32_t num)\n{\n    uint32_t num1, num2;\n    memcpy(&num1, nonce + (crypto_box_NONCEBYTES - sizeof(num1)), sizeof(num1));\n    num1 = ntohl(num1);\n    num2 = num + num1;\n\n    if (num2 < num1) {\n        uint32_t i;\n\n        for (i = crypto_box_NONCEBYTES - sizeof(num1); i != 0; --i) {\n            ++nonce[i - 1];\n\n            if (nonce[i - 1] != 0)\n                break;\n        }\n    }\n\n    num2 = htonl(num2);\n    memcpy(nonce + (crypto_box_NONCEBYTES - sizeof(num2)), &num2, sizeof(num2));\n}\n\nSTART_TEST(test_increment_nonce)\n{\n    long long unsigned int i;\n\n    uint8_t n[crypto_box_NONCEBYTES];\n\n    for (i = 0; i < crypto_box_NONCEBYTES; ++i)\n        n[i] = rand();\n\n    uint8_t n1[crypto_box_NONCEBYTES];\n\n    memcpy(n1, n, crypto_box_NONCEBYTES);\n\n    for (i = 0; i < (1 << 18); ++i) {\n        increment_nonce_number_cmp(n, 1);\n        increment_nonce(n1);\n        ck_assert_msg(memcmp(n, n1, crypto_box_NONCEBYTES) == 0, \"Bad increment_nonce function\");\n    }\n\n    for (i = 0; i < (1 << 18); ++i) {\n        uint32_t r = rand();\n        increment_nonce_number_cmp(n, r);\n        increment_nonce_number(n1, r);\n        ck_assert_msg(memcmp(n, n1, crypto_box_NONCEBYTES) == 0, \"Bad increment_nonce_number function\");\n    }\n}\nEND_TEST\n\nSuite *crypto_suite(void)\n{\n    Suite *s = suite_create(\"Crypto\");\n\n    DEFTESTCASE(known);\n    DEFTESTCASE(fast_known);\n    DEFTESTCASE_SLOW(endtoend, 15); /* waiting up to 15 seconds */\n    DEFTESTCASE(large_data);\n    DEFTESTCASE(large_data_symmetric);\n    DEFTESTCASE_SLOW(increment_nonce, 20);\n\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *crypto = crypto_suite();\n    SRunner *test_runner = srunner_create(crypto);\n    int number_failed = 0;\n\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/dht_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/param.h>\n#include <time.h>\n\n#include \"../toxcore/tox.h\"\n#include \"../toxcore/DHT.c\"\n\n#include \"helpers.h\"\n\n#define swap(x,y) do \\\n   { unsigned char swap_temp[sizeof(x) == sizeof(y) ? (signed)sizeof(x) : -1]; \\\n     memcpy(swap_temp,&y,sizeof(x)); \\\n     memcpy(&y,&x,       sizeof(x)); \\\n     memcpy(&x,swap_temp,sizeof(x)); \\\n    } while(0)\n\n\nvoid mark_bad(IPPTsPng *ipptp)\n{\n    ipptp->timestamp = unix_time() - 2 * BAD_NODE_TIMEOUT;\n    ipptp->hardening.routes_requests_ok = 0;\n    ipptp->hardening.send_nodes_ok = 0;\n    ipptp->hardening.testing_requests = 0;\n}\n\nvoid mark_possible_bad(IPPTsPng *ipptp)\n{\n    ipptp->timestamp = unix_time();\n    ipptp->hardening.routes_requests_ok = 0;\n    ipptp->hardening.send_nodes_ok = 0;\n    ipptp->hardening.testing_requests = 0;\n}\n\nvoid mark_good(IPPTsPng *ipptp)\n{\n    ipptp->timestamp = unix_time();\n    ipptp->hardening.routes_requests_ok = (HARDENING_ALL_OK >> 0) & 1;\n    ipptp->hardening.send_nodes_ok = (HARDENING_ALL_OK >> 1) & 1;\n    ipptp->hardening.testing_requests = (HARDENING_ALL_OK >> 2) & 1;\n}\n\nvoid mark_all_good(Client_data *list, uint32_t length, uint8_t ipv6)\n{\n    uint32_t i;\n\n    for (i = 0; i < length; ++i) {\n        if (ipv6)\n            mark_good(&list[i].assoc6);\n        else\n            mark_good(&list[i].assoc4);\n    }\n}\n\n/* Returns 1 if public_key has a furthest distance to comp_client_id\n   than all public_key's  in the list */\nuint8_t is_furthest(const uint8_t *comp_client_id, Client_data *list, uint32_t length, const uint8_t *public_key)\n{\n    uint32_t i;\n\n    for (i = 0; i < length; ++i)\n        if (id_closest(comp_client_id, public_key, list[i].public_key) == 1)\n            return 0;\n\n    return 1;\n}\n\nint client_in_list(Client_data *list, uint32_t length, const uint8_t *public_key)\n{\n    int i;\n\n    for (i = 0; i < (int)length; ++i)\n        if (id_equal(public_key, list[i].public_key))\n            return i;\n\n    return -1;\n}\n\nvoid test_addto_lists_update(DHT            *dht,\n                             Client_data    *list,\n                             uint32_t        length,\n                             IP_Port        *ip_port)\n{\n    int used, test, test1, test2, found;\n    IP_Port test_ipp;\n    uint8_t test_id[crypto_box_PUBLICKEYBYTES];\n    uint8_t ipv6 = ip_port->ip.family == AF_INET6 ? 1 : 0;\n\n    // check id update for existing ip_port\n    test = rand() % length;\n    ipport_copy(&test_ipp, ipv6 ? &list[test].assoc6.ip_port : &list[test].assoc4.ip_port);\n\n    randombytes(test_id, sizeof(test_id));\n    used = addto_lists(dht, test_ipp, test_id);\n    ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n    // it is possible to have ip_port duplicates in the list, so ip_port @ found not always equal to ip_port @ test\n    found = client_in_list(list, length, test_id);\n    ck_assert_msg(found >= 0, \"Client id is not in the list\");\n    ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[found].assoc6.ip_port : &list[found].assoc4.ip_port),\n                  \"Client IP_Port is incorrect\");\n\n    // check ip_port update for existing id\n    test = rand() % length;\n    test_ipp.port = rand() % TOX_PORT_DEFAULT;\n    id_copy(test_id, list[test].public_key);\n\n    used = addto_lists(dht, test_ipp, test_id);\n    ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n    // it is not possible to have id duplicates in the list, so id @ found must be equal id @ test\n    ck_assert_msg(client_in_list(list, length, test_id) == test, \"Client id is not in the list\");\n    ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test].assoc6.ip_port : &list[test].assoc4.ip_port),\n                  \"Client IP_Port is incorrect\");\n\n    // check ip_port update for existing id and ip_port (... port ... id ...)\n    test1 = rand() % (length / 2);\n    test2 = rand() % (length / 2) + length / 2;\n\n    ipport_copy(&test_ipp, ipv6 ? &list[test1].assoc6.ip_port : &list[test1].assoc4.ip_port);\n    id_copy(test_id, list[test2].public_key);\n\n    if (ipv6) list[test2].assoc6.ip_port.port = -1;\n    else list[test2].assoc4.ip_port.port = -1;\n\n    used = addto_lists(dht, test_ipp, test_id);\n    ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n    ck_assert_msg(client_in_list(list, length, test_id) == test2, \"Client id is not in the list\");\n    ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test2].assoc6.ip_port : &list[test2].assoc4.ip_port),\n                  \"Client IP_Port is incorrect\");\n\n    // check ip_port update for existing id and ip_port (... id ... port ...)\n    test1 = rand() % (length / 2);\n    test2 = rand() % (length / 2) + length / 2;\n\n    ipport_copy(&test_ipp, ipv6 ? &list[test2].assoc6.ip_port : &list[test2].assoc4.ip_port);\n    id_copy(test_id, list[test1].public_key);\n\n    if (ipv6) list[test1].assoc6.ip_port.port = -1;\n    else list[test1].assoc4.ip_port.port = -1;\n\n    used = addto_lists(dht, test_ipp, test_id);\n    ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n    ck_assert_msg(client_in_list(list, length, test_id) == test1, \"Client id is not in the list\");\n    ck_assert_msg(ipport_equal(&test_ipp, ipv6 ? &list[test1].assoc6.ip_port : &list[test1].assoc4.ip_port),\n                  \"Client IP_Port is incorrect\");\n}\n\nvoid test_addto_lists_bad(DHT            *dht,\n                          Client_data    *list,\n                          uint32_t        length,\n                          IP_Port        *ip_port)\n{\n    // check \"bad\" clients replacement\n    int used, test1, test2, test3;\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES], test_id1[crypto_box_PUBLICKEYBYTES], test_id2[crypto_box_PUBLICKEYBYTES],\n            test_id3[crypto_box_PUBLICKEYBYTES];\n    uint8_t ipv6 = ip_port->ip.family == AF_INET6 ? 1 : 0;\n\n    randombytes(public_key, sizeof(public_key));\n    mark_all_good(list, length, ipv6);\n\n    test1 = rand() % (length / 3);\n    test2 = rand() % (length / 3) + length / 3;\n    test3 = rand() % (length / 3) + 2 * length / 3;\n    ck_assert_msg(!(test1 == test2 || test1 == test3 || test2 == test3), \"Wrong test indices are chosen\");\n\n    id_copy((uint8_t *)&test_id1, list[test1].public_key);\n    id_copy((uint8_t *)&test_id2, list[test2].public_key);\n    id_copy((uint8_t *)&test_id3, list[test3].public_key);\n\n    // mark nodes as \"bad\"\n    if (ipv6) {\n        mark_bad(&list[test1].assoc6);\n        mark_bad(&list[test2].assoc6);\n        mark_bad(&list[test3].assoc6);\n    } else {\n        mark_bad(&list[test1].assoc4);\n        mark_bad(&list[test2].assoc4);\n        mark_bad(&list[test3].assoc4);\n    }\n\n    ip_port->port += 1;\n    used = addto_lists(dht, *ip_port, public_key);\n    ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n\n    ck_assert_msg(client_in_list(list, length, public_key) >= 0, \"Client id is not in the list\");\n    ck_assert_msg(client_in_list(list, length, test_id2) >= 0, \"Wrong bad client removed\");\n    ck_assert_msg(client_in_list(list, length, test_id3) >= 0, \"Wrong bad client removed\");\n}\n\nvoid test_addto_lists_possible_bad(DHT            *dht,\n                                   Client_data    *list,\n                                   uint32_t        length,\n                                   IP_Port        *ip_port,\n                                   const uint8_t  *comp_client_id)\n{\n    // check \"possibly bad\" clients replacement\n    int used, test1, test2, test3;\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES], test_id1[crypto_box_PUBLICKEYBYTES], test_id2[crypto_box_PUBLICKEYBYTES],\n            test_id3[crypto_box_PUBLICKEYBYTES];\n    uint8_t ipv6 = ip_port->ip.family == AF_INET6 ? 1 : 0;\n\n    randombytes(public_key, sizeof(public_key));\n    mark_all_good(list, length, ipv6);\n\n    test1 = rand() % (length / 3);\n    test2 = rand() % (length / 3) + length / 3;\n    test3 = rand() % (length / 3) + 2 * length / 3;\n    ck_assert_msg(!(test1 == test2 || test1 == test3 || test2 == test3), \"Wrong test indices are chosen\");\n\n    id_copy((uint8_t *)&test_id1, list[test1].public_key);\n    id_copy((uint8_t *)&test_id2, list[test2].public_key);\n    id_copy((uint8_t *)&test_id3, list[test3].public_key);\n\n    // mark nodes as \"possibly bad\"\n    if (ipv6) {\n        mark_possible_bad(&list[test1].assoc6);\n        mark_possible_bad(&list[test2].assoc6);\n        mark_possible_bad(&list[test3].assoc6);\n    } else {\n        mark_possible_bad(&list[test1].assoc4);\n        mark_possible_bad(&list[test2].assoc4);\n        mark_possible_bad(&list[test3].assoc4);\n    }\n\n    ip_port->port += 1;\n    used = addto_lists(dht, *ip_port, public_key);\n    ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n\n    ck_assert_msg(client_in_list(list, length, public_key) >= 0, \"Client id is not in the list\");\n\n    int inlist_id1 = client_in_list(list, length, test_id1) >= 0;\n    int inlist_id2 = client_in_list(list, length, test_id2) >= 0;\n    int inlist_id3 = client_in_list(list, length, test_id3) >= 0;\n\n    ck_assert_msg(inlist_id1 + inlist_id2 + inlist_id3 == 2, \"Wrong client removed\");\n\n    if (!inlist_id1) {\n        ck_assert_msg(id_closest(comp_client_id, test_id2, test_id1) == 1,\n                      \"Id has been removed but is closer to than another one\");\n        ck_assert_msg(id_closest(comp_client_id, test_id3, test_id1) == 1,\n                      \"Id has been removed but is closer to than another one\");\n    } else if (!inlist_id2) {\n        ck_assert_msg(id_closest(comp_client_id, test_id1, test_id2) == 1,\n                      \"Id has been removed but is closer to than another one\");\n        ck_assert_msg(id_closest(comp_client_id, test_id3, test_id2) == 1,\n                      \"Id has been removed but is closer to than another one\");\n    } else if (!inlist_id3) {\n        ck_assert_msg(id_closest(comp_client_id, test_id1, test_id3) == 1,\n                      \"Id has been removed but is closer to than another one\");\n        ck_assert_msg(id_closest(comp_client_id, test_id2, test_id3) == 1,\n                      \"Id has been removed but is closer to than another one\");\n    }\n}\n\nvoid test_addto_lists_good(DHT            *dht,\n                           Client_data    *list,\n                           uint32_t        length,\n                           IP_Port        *ip_port,\n                           const uint8_t  *comp_client_id)\n{\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t ipv6 = ip_port->ip.family == AF_INET6 ? 1 : 0;\n\n    mark_all_good(list, length, ipv6);\n\n    // check \"good\" client id replacement\n    do {\n        randombytes(public_key, sizeof(public_key));\n    } while (is_furthest(comp_client_id, list, length, public_key));\n\n    ip_port->port += 1;\n    addto_lists(dht, *ip_port, public_key);\n    ck_assert_msg(client_in_list(list, length, public_key) >= 0, \"Good client id is not in the list\");\n\n    // check \"good\" client id skip\n    do {\n        randombytes(public_key, sizeof(public_key));\n    } while (!is_furthest(comp_client_id, list, length, public_key));\n\n    ip_port->port += 1;\n    addto_lists(dht, *ip_port, public_key);\n    ck_assert_msg(client_in_list(list, length, public_key) == -1, \"Good client id is in the list\");\n}\n\nvoid test_addto_lists(IP ip)\n{\n    Networking_Core *net = new_networking(ip, TOX_PORT_DEFAULT);\n    ck_assert_msg(net != 0, \"Failed to create Networking_Core\");\n\n    DHT *dht = new_DHT(net);\n    ck_assert_msg(dht != 0, \"Failed to create DHT\");\n\n    IP_Port ip_port = { .ip = ip, .port = TOX_PORT_DEFAULT };\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    int i, used;\n\n    // check lists filling\n    for (i = 0; i < MAX(LCLIENT_LIST, MAX_FRIEND_CLIENTS); ++i) {\n        randombytes(public_key, sizeof(public_key));\n        used = addto_lists(dht, ip_port, public_key);\n        ck_assert_msg(used == dht->num_friends + 1, \"Wrong number of added clients with existing ip_port\");\n    }\n\n    for (i = 0; i < MAX(LCLIENT_LIST, MAX_FRIEND_CLIENTS); ++i) {\n        ip_port.port += 1;\n        used = addto_lists(dht, ip_port, public_key);\n        ck_assert_msg(used == dht->num_friends + 1, \"Wrong number of added clients with existing public_key\");\n    }\n\n    for (i = 0; i < MAX(LCLIENT_LIST, MAX_FRIEND_CLIENTS); ++i) {\n        ip_port.port += 1;\n        randombytes(public_key, sizeof(public_key));\n        used = addto_lists(dht, ip_port, public_key);\n        ck_assert_msg(used >= 1, \"Wrong number of added clients\");\n    }\n\n    /*check: Current behavior if there are two clients with the same id is\n     * to replace the first ip by the second. */\n    test_addto_lists_update(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port);\n\n    for (i = 0; i < dht->num_friends; ++i)\n        test_addto_lists_update(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port);\n\n    // check \"bad\" entries\n    test_addto_lists_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port);\n\n    for (i = 0; i < dht->num_friends; ++i)\n        test_addto_lists_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port);\n\n    // check \"possibly bad\" entries\n    /*\n    test_addto_lists_possible_bad(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key);\n\n    for (i = 0; i < dht->num_friends; ++i)\n        test_addto_lists_possible_bad(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port,\n                                      dht->friends_list[i].public_key);\n    */\n    // check \"good\" entries\n    test_addto_lists_good(dht, dht->close_clientlist, LCLIENT_LIST, &ip_port, dht->self_public_key);\n\n    for (i = 0; i < dht->num_friends; ++i)\n        test_addto_lists_good(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, &ip_port,\n                              dht->friends_list[i].public_key);\n\n    kill_DHT(dht);\n    kill_networking(net);\n}\n\nSTART_TEST(test_addto_lists_ipv4)\n{\n    IP ip;\n    ip_init(&ip, 0);\n    test_addto_lists(ip);\n\n}\nEND_TEST\n\nSTART_TEST(test_addto_lists_ipv6)\n{\n    IP ip;\n    ip_init(&ip, 1);\n    test_addto_lists(ip);\n\n}\nEND_TEST\n\n#define DHT_DEFAULT_PORT (TOX_PORT_DEFAULT + 20)\n\n#define DHT_LIST_LENGTH 128\n\nvoid print_pk(uint8_t *public_key)\n{\n    uint32_t j;\n\n    for (j = 0; j < crypto_box_PUBLICKEYBYTES; j++) {\n        printf(\"%02hhX\", public_key[j]);\n    }\n\n    printf(\"\\n\");\n}\n\nvoid test_add_to_list(uint8_t cmp_list[][crypto_box_PUBLICKEYBYTES + 1], unsigned int length, const uint8_t *pk,\n                      const uint8_t *cmp_pk)\n{\n    uint8_t p_b[crypto_box_PUBLICKEYBYTES];\n    unsigned int i;\n\n    for (i = 0; i < length; ++i) {\n        if (!cmp_list[i][crypto_box_PUBLICKEYBYTES]) {\n            memcpy(cmp_list[i], pk, crypto_box_PUBLICKEYBYTES);\n            cmp_list[i][crypto_box_PUBLICKEYBYTES] = 1;\n            return;\n        } else {\n            if (memcmp(cmp_list[i], pk, crypto_box_PUBLICKEYBYTES) == 0) {\n                return;\n            }\n        }\n    }\n\n    for (i = 0; i < length; ++i) {\n        if (id_closest(cmp_pk, cmp_list[i], pk) == 2) {\n            memcpy(p_b, cmp_list[i], crypto_box_PUBLICKEYBYTES);\n            memcpy(cmp_list[i], pk, crypto_box_PUBLICKEYBYTES);\n            test_add_to_list(cmp_list, length, p_b, cmp_pk);\n            break;\n        }\n    }\n}\n\n#define NUM_DHT 100\n\nvoid test_list_main()\n{\n    DHT *dhts[NUM_DHT];\n\n    uint8_t cmp_list1[NUM_DHT][MAX_FRIEND_CLIENTS][crypto_box_PUBLICKEYBYTES + 1];\n    memset(cmp_list1, 0, sizeof(cmp_list1));\n\n    IP ip;\n    ip_init(&ip, 1);\n\n    unsigned int i, j, k, l;\n\n    for (i = 0; i < NUM_DHT; ++i) {\n        IP ip;\n        ip_init(&ip, 1);\n\n        dhts[i] = new_DHT(new_networking(ip, DHT_DEFAULT_PORT + i));\n        ck_assert_msg(dhts[i] != 0, \"Failed to create dht instances %u\", i);\n        ck_assert_msg(dhts[i]->net->port != DHT_DEFAULT_PORT + i, \"Bound to wrong port\");\n    }\n\n    for (j = 0; j < NUM_DHT; ++j) {\n        for (i = 1; i < NUM_DHT; ++i) {\n            test_add_to_list(cmp_list1[j], MAX_FRIEND_CLIENTS, dhts[(i + j) % NUM_DHT]->self_public_key, dhts[j]->self_public_key);\n        }\n    }\n\n    for (j = 0; j < NUM_DHT; ++j) {\n        for (i = 0; i < NUM_DHT; ++i) {\n            if (i == j)\n                continue;\n\n            IP_Port ip_port;\n            ip_init(&ip_port.ip, 0);\n            ip_port.ip.ip4.uint32 = rand();\n            ip_port.port = rand() % (UINT16_MAX - 1);\n            ++ip_port.port;\n            addto_lists(dhts[j], ip_port, dhts[i]->self_public_key);\n        }\n    }\n\n    /*\n        print_pk(dhts[0]->self_public_key);\n\n        for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {\n            printf(\"----Entry %u----\\n\", i);\n\n            print_pk(cmp_list1[i]);\n        }\n    */\n    unsigned int m_count = 0;\n\n    for (l = 0; l < NUM_DHT; ++l) {\n        for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {\n            for (j = 1; j < NUM_DHT; ++j) {\n                if (memcmp(cmp_list1[l][i], dhts[(l + j) % NUM_DHT]->self_public_key, crypto_box_PUBLICKEYBYTES) != 0)\n                    continue;\n\n                unsigned int count = 0;\n\n                for (k = 0; k < LCLIENT_LIST; ++k) {\n                    if (memcmp(dhts[l]->self_public_key, dhts[(l + j) % NUM_DHT]->close_clientlist[k].public_key,\n                               crypto_box_PUBLICKEYBYTES) == 0)\n                        ++count;\n                }\n\n                if (count != 1) {\n                    print_pk(dhts[l]->self_public_key);\n\n                    for (k = 0; k < MAX_FRIEND_CLIENTS; ++k) {\n                        printf(\"----Entry %u----\\n\", k);\n\n                        print_pk(cmp_list1[l][k]);\n                    }\n\n                    for (k = 0; k < LCLIENT_LIST; ++k) {\n                        printf(\"----Closel %u----\\n\", k);\n                        print_pk(dhts[(l + j) % NUM_DHT]->close_clientlist[k].public_key);\n                    }\n\n                    print_pk(dhts[(l + j) % NUM_DHT]->self_public_key);\n                }\n\n                ck_assert_msg(count == 1, \"Nodes in search don't know ip of friend. %u %u %u\", i, j, count);\n\n                Node_format ln[MAX_SENT_NODES];\n                int n = get_close_nodes(dhts[(l + j) % NUM_DHT], dhts[l]->self_public_key, ln, 0, 1, 0);\n                ck_assert_msg(n == MAX_SENT_NODES, \"bad num close %u | %u %u\", n, i, j);\n\n                count = 0;\n\n                for (k = 0; k < MAX_SENT_NODES; ++k) {\n                    if (memcmp(dhts[l]->self_public_key, ln[k].public_key, crypto_box_PUBLICKEYBYTES) == 0)\n                        ++count;\n                }\n\n                ck_assert_msg(count == 1, \"Nodes in search don't know ip of friend. %u %u %u\", i, j, count);\n                /*\n                            for (k = 0; k < MAX_SENT_NODES; ++k) {\n                                printf(\"----gn %u----\\n\", k);\n                                print_pk(ln[k].public_key);\n                            }*/\n                ++m_count;\n            }\n        }\n    }\n\n    ck_assert_msg(m_count == (NUM_DHT) * (MAX_FRIEND_CLIENTS), \"Bad count. %u != %u\", m_count,\n                  (NUM_DHT) * (MAX_FRIEND_CLIENTS));\n\n    for (i = 0; i < NUM_DHT; ++i) {\n        void *n = dhts[i]->net;\n        kill_DHT(dhts[i]);\n        kill_networking(n);\n    }\n}\n\n\nSTART_TEST(test_list)\n{\n    unsigned int i;\n\n    for (i = 0; i < 10; ++i)\n        test_list_main();\n}\nEND_TEST\n\nvoid ip_callback(void *data, int32_t number, IP_Port ip_port)\n{\n\n\n}\n\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n#define NUM_DHT_FRIENDS 20\n\nSTART_TEST(test_DHT_test)\n{\n    uint32_t to_comp = 8394782;\n    DHT *dhts[NUM_DHT];\n\n    unsigned int i, j;\n\n    for (i = 0; i < NUM_DHT; ++i) {\n        IP ip;\n        ip_init(&ip, 1);\n\n        dhts[i] = new_DHT(new_networking(ip, DHT_DEFAULT_PORT + i));\n        ck_assert_msg(dhts[i] != 0, \"Failed to create dht instances %u\", i);\n        ck_assert_msg(dhts[i]->net->port != DHT_DEFAULT_PORT + i, \"Bound to wrong port\");\n    }\n\n    struct {\n        uint16_t tox1;\n        uint16_t tox2;\n    } pairs[NUM_DHT_FRIENDS];\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    unsigned int num_f = 0;\n\n    for (i = 0; i < NUM_DHT_FRIENDS; ++i) {\nloop_top:\n        pairs[i].tox1 = rand() % NUM_DHT;\n        pairs[i].tox2 = (pairs[i].tox1 + (rand() % (NUM_DHT - 1)) + 1) % NUM_DHT;\n\n        for (j = 0; j < i; ++j) {\n            if (pairs[j].tox2 == pairs[i].tox2 && pairs[j].tox1 == pairs[i].tox1)\n                goto loop_top;\n        }\n\n        uint16_t lock_count = 0;\n        ck_assert_msg(DHT_addfriend(dhts[pairs[i].tox2], dhts[pairs[i].tox1]->self_public_key, &ip_callback, &to_comp, 1337,\n                                    &lock_count) == 0, \"Failed to add friend\");\n        ck_assert_msg(lock_count == 1, \"bad lock count: %u %u\", lock_count, i);\n    }\n\n    for (i = 0; i < NUM_DHT; ++i) {\n        IP_Port ip_port;\n        ip_init(&ip_port.ip, 1);\n        ip_port.ip.ip6.uint8[15] = 1;\n        ip_port.port = htons(DHT_DEFAULT_PORT + i);\n        DHT_bootstrap(dhts[(i - 1) % NUM_DHT], ip_port, dhts[i]->self_public_key);\n    }\n\n    while (1) {\n        uint16_t counter = 0;\n\n        for (i = 0; i < NUM_DHT_FRIENDS; ++i) {\n            IP_Port a;\n\n            if (DHT_getfriendip(dhts[pairs[i].tox2], dhts[pairs[i].tox1]->self_public_key, &a) == 1)\n                ++counter;\n        }\n\n        if (counter == NUM_DHT_FRIENDS) {\n            break;\n        }\n\n        for (i = 0; i < NUM_DHT; ++i) {\n            networking_poll(dhts[i]->net);\n            do_DHT(dhts[i]);\n        }\n\n        c_sleep(500);\n    }\n\n    for (i = 0; i < NUM_DHT; ++i) {\n        void *n = dhts[i]->net;\n        kill_DHT(dhts[i]);\n        kill_networking(n);\n    }\n}\nEND_TEST\n\nSuite *dht_suite(void)\n{\n    Suite *s = suite_create(\"DHT\");\n\n    //DEFTESTCASE(addto_lists_ipv4);\n    //DEFTESTCASE(addto_lists_ipv6);\n    DEFTESTCASE_SLOW(list, 20);\n    DEFTESTCASE_SLOW(DHT_test, 50);\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *dht = dht_suite();\n    SRunner *test_runner = srunner_create(dht);\n\n    int number_failed = 0;\n    //srunner_set_fork_status(test_runner, CK_NOFORK);\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/encryptsave_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"helpers.h\"\n\n#include \"../toxcore/tox.h\"\n\n#include \"../toxencryptsave/toxencryptsave.h\"\n#include \"../toxcore/crypto_core.h\"\n#ifdef VANILLA_NACL\n#include \"../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h\"\n#endif\n\nunsigned 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};\nunsigned 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};\nchar *pw = \"hunter2\";\nunsigned int pwlen = 7;\n\nunsigned 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};\n// same as above, except standard opslimit instead of extra ops limit for test_known_kdf, and hash pw before kdf for compat\n\n/* cause I'm shameless */\nvoid accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    if (length == 7 && memcmp(\"Gentoo\", data, 7) == 0) {\n        tox_friend_add_norequest(m, public_key, 0);\n    }\n}\n\nSTART_TEST(test_known_kdf)\n{\n    unsigned char out[crypto_box_BEFORENMBYTES];\n    crypto_pwhash_scryptsalsa208sha256(out,\n                                       crypto_box_BEFORENMBYTES,\n                                       pw,\n                                       pwlen,\n                                       salt,\n                                       crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 8,\n                                       crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);\n    ck_assert_msg(memcmp(out, known_key, crypto_box_BEFORENMBYTES) == 0, \"derived key is wrong\");\n}\nEND_TEST\n\nSTART_TEST(test_save_friend)\n{\n    Tox *tox1 = tox_new(0, 0);\n    Tox *tox2 = tox_new(0, 0);\n    ck_assert_msg(tox1 || tox2, \"Failed to create 2 tox instances\");\n    uint32_t to_compare = 974536;\n    tox_callback_friend_request(tox2, accept_friend_request, &to_compare);\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox2, address);\n    uint32_t test = tox_friend_add(tox1, address, (uint8_t *)\"Gentoo\", 7, 0);\n    ck_assert_msg(test != UINT32_MAX, \"Failed to add friend\");\n\n    size_t size = tox_get_savedata_size(tox1);\n    uint8_t data[size];\n    tox_get_savedata(tox1, data);\n    size_t size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;\n    uint8_t enc_data[size2];\n    TOX_ERR_ENCRYPTION error1;\n    bool ret = tox_pass_encrypt(data, size, \"correcthorsebatterystaple\", 25, enc_data, &error1);\n    ck_assert_msg(ret, \"failed to encrypted save: %u\", error1);\n    ck_assert_msg(tox_is_data_encrypted(enc_data), \"magic number missing\");\n\n    struct Tox_Options options;\n    tox_options_default(&options);\n    options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;\n    options.savedata_data = enc_data;\n    options.savedata_length = size2;\n\n    TOX_ERR_NEW err2;\n    Tox *tox3 = tox_new(&options, &err2);\n    ck_assert_msg(err2 == TOX_ERR_NEW_LOAD_ENCRYPTED, \"wrong error! %u. should fail with %u\", err2,\n                  TOX_ERR_NEW_LOAD_ENCRYPTED);\n    uint8_t dec_data[size];\n    TOX_ERR_DECRYPTION err3;\n    ret = tox_pass_decrypt(enc_data, size2, \"correcthorsebatterystaple\", 25, dec_data, &err3);\n    ck_assert_msg(ret, \"failed to decrypt save: %u\", err3);\n    options.savedata_data = dec_data;\n    options.savedata_length = size;\n    tox3 = tox_new(&options, &err2);\n    ck_assert_msg(err2 == TOX_ERR_NEW_OK, \"failed to load from decrypted data: %u\", err2);\n    uint8_t address2[TOX_PUBLIC_KEY_SIZE];\n    ret = tox_friend_get_public_key(tox3, 0, address2, 0);\n    ck_assert_msg(ret, \"no friends!\");\n    ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, \"addresses don't match!\");\n\n    size = tox_get_savedata_size(tox3);\n    uint8_t data2[size];\n    tox_get_savedata(tox3, data2);\n    TOX_PASS_KEY key;\n    memcpy(key.salt, salt, 32);\n    memcpy(key.key, known_key2, crypto_box_BEFORENMBYTES);\n    size2 = size + TOX_PASS_ENCRYPTION_EXTRA_LENGTH;\n    uint8_t encdata2[size2];\n    ret = tox_pass_key_encrypt(data2, size, &key, encdata2, &error1);\n    ck_assert_msg(ret, \"failed to key encrypt %u\", error1);\n    ck_assert_msg(tox_is_data_encrypted(encdata2), \"magic number the second missing\");\n\n    uint8_t out1[size], out2[size];\n    ret = tox_pass_decrypt(encdata2, size2, pw, pwlen, out1, &err3);\n    ck_assert_msg(ret, \"failed to pw decrypt %u\", err3);\n    ret = tox_pass_key_decrypt(encdata2, size2, &key, out2, &err3);\n    ck_assert_msg(ret, \"failed to key decrypt %u\", err3);\n    ck_assert_msg(memcmp(out1, out2, size) == 0, \"differing output data\");\n\n    // and now with the code in use (I only bothered with manually to debug this, and it seems a waste\n    // to remove the manual check now that it's there)\n    options.savedata_data = out1;\n    options.savedata_length = size;\n    Tox *tox4 = tox_new(&options, &err2);\n    ck_assert_msg(err2 == TOX_ERR_NEW_OK, \"failed to new the third\");\n    uint8_t address5[TOX_PUBLIC_KEY_SIZE];\n    ret = tox_friend_get_public_key(tox4, 0, address5, 0);\n    ck_assert_msg(ret, \"no friends! the third\");\n    ck_assert_msg(memcmp(address, address2, TOX_PUBLIC_KEY_SIZE) == 0, \"addresses don't match! the third\");\n\n    tox_kill(tox1);\n    tox_kill(tox2);\n    tox_kill(tox3);\n    tox_kill(tox4);\n}\nEND_TEST\n\nSTART_TEST(test_keys)\n{\n    TOX_ERR_ENCRYPTION encerr;\n    TOX_ERR_DECRYPTION decerr;\n    TOX_ERR_KEY_DERIVATION keyerr;\n    TOX_PASS_KEY key;\n    bool ret = tox_derive_key_from_pass(\"123qweasdzxc\", 12, &key, &keyerr);\n    ck_assert_msg(ret, \"generic failure 1: %u\", keyerr);\n    uint8_t *string = \"No Patrick, mayonnaise is not an instrument.\"; // 44\n\n    uint8_t encrypted[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH];\n    ret = tox_pass_key_encrypt(string, 44, &key, encrypted, &encerr);\n    ck_assert_msg(ret, \"generic failure 2: %u\", encerr);\n\n    uint8_t encrypted2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH];\n    ret = tox_pass_encrypt(string, 44, \"123qweasdzxc\", 12, encrypted2, &encerr);\n    ck_assert_msg(ret, \"generic failure 3: %u\", encerr);\n\n    uint8_t out1[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH];\n    uint8_t out2[44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH];\n\n    ret = tox_pass_key_decrypt(encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, &key, out1, &decerr);\n    ck_assert_msg(ret, \"generic failure 4: %u\", decerr);\n    ck_assert_msg(memcmp(out1, string, 44) == 0, \"decryption 1 failed\");\n\n    ret = tox_pass_decrypt(encrypted2, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, \"123qweasdzxc\", 12, out2, &decerr);\n    ck_assert_msg(ret, \"generic failure 5: %u\", decerr);\n    ck_assert_msg(memcmp(out2, string, 44) == 0, \"decryption 2 failed\");\n\n    ret = tox_pass_decrypt(encrypted2, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, NULL, 0, out2, &decerr);\n    ck_assert_msg(!ret, \"Decrypt succeeded with wrong pass\");\n    ck_assert_msg(decerr != TOX_ERR_DECRYPTION_FAILED, \"Bad error code %u\", decerr);\n\n    // test that pass_decrypt can decrypt things from pass_key_encrypt\n    ret = tox_pass_decrypt(encrypted, 44 + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, \"123qweasdzxc\", 12, out1, &decerr);\n    ck_assert_msg(ret, \"generic failure 6: %u\", decerr);\n    ck_assert_msg(memcmp(out1, string, 44) == 0, \"decryption 3 failed\");\n\n    uint8_t salt[TOX_PASS_SALT_LENGTH];\n    ck_assert_msg(tox_get_salt(encrypted, salt), \"couldn't get salt\");\n    TOX_PASS_KEY key2;\n    ret = tox_derive_key_with_salt(\"123qweasdzxc\", 12, salt, &key2, &keyerr);\n    ck_assert_msg(ret, \"generic failure 7: %u\", keyerr);\n    ck_assert_msg(0 == memcmp(&key, &key2, sizeof(TOX_PASS_KEY)), \"salt comparison failed\");\n}\nEND_TEST\n\nSuite *encryptsave_suite(void)\n{\n    Suite *s = suite_create(\"encryptsave\");\n\n    DEFTESTCASE_SLOW(known_kdf, 60);\n    DEFTESTCASE_SLOW(save_friend, 20);\n    DEFTESTCASE_SLOW(keys, 30);\n\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *encryptsave =  encryptsave_suite();\n    SRunner *test_runner = srunner_create(encryptsave);\n\n    int number_failed = 0;\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n\n"
  },
  {
    "path": "auto_tests/friends_test.c",
    "content": "/* Unit testing for friend requests, statuses, and messages.\n *  Purpose: Check that messaging functions actually do what\n *          they're supposed to by setting up two local clients.\n *\n *  Design: (Subject to change.)\n *      1. Parent sends a friend request, and waits for a response.\n *          It it doesn't get one, it kills the child.\n *      2. Child gets friend request, accepts, then waits for a status change.\n *      3. The parent waits on a status change, killing the child if it takes\n *          too long.\n *      4. The child gets the status change, then sends a message. After that,\n *          it returns. If if doesn't get the status change, it just loops forever.\n *      5. After getting the status change, the parent waits for a message, on getting\n *          one, it waits on the child to return, then returns 0.\n *\n *  Note about \"waiting\":\n *      Wait time is decided by WAIT_COUNT and WAIT_TIME. c_sleep(WAIT_TIME) WAIT_COUNT\n *      times. This is used both to ensure that we don't loop forever on a broken build,\n *      and that we don't get too slow with messaging. The current time is 15 seconds. */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/friend_requests.h\"\n#include \"../toxcore/Messenger.h\"\n#include <assert.h>\n#include <unistd.h>\n#include <sys/mman.h>\n#include <signal.h>\n#include <sys/wait.h>\n\n#define WAIT_COUNT 30\n#define WAIT_TIME 500\n\n#ifndef MAP_ANONYMOUS\n#define MAP_ANONYMOUS MAP_ANON\n#endif\n\n/* first step, second step */\n#define FIRST_FLAG 0x1\n#define SECOND_FLAG 0x2\n\n/* ensure that we sleep in milliseconds */\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(x)\n#else\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n#define PORT 33445\n\nstatic Messenger *m;\n\nuint8_t *parent_id = NULL;\nuint8_t *child_id = NULL;\n\npid_t child_pid = 0;\nint request_flags = 0;\n\nvoid do_tox(DHT *dht)\n{\n    static int dht_on = 0;\n\n    if (!dht_on && DHT_isconnected(dht)) {\n        dht_on = 1;\n    } else if (dht_on && !DHT_isconnected(dht)) {\n        dht_on = 0;\n    }\n\n    doMessenger(m);\n}\n\nvoid parent_confirm_message(Messenger *m, int num, uint8_t *data, uint16_t length, void *userdata)\n{\n    puts(\"OK\");\n    request_flags |= SECOND_FLAG;\n}\n\nvoid parent_confirm_status(Messenger *m, int num, uint8_t *data, uint16_t length, void *userdata)\n{\n    puts(\"OK\");\n    request_flags |= FIRST_FLAG;\n}\n\nint parent_friend_request(DHT *dht)\n{\n    char *message = \"Watson, come here, I need you.\";\n    int len = strlen(message);\n    int i = 0;\n\n    fputs(\"Sending child request.\", stdout);\n    fflush(stdout);\n\n    m_addfriend(m, child_id, (uint8_t *)message, len);\n\n    /* wait on the status change */\n    for (i = 0; i < WAIT_COUNT; i++) {\n        do_tox(dht);\n\n        if (request_flags & FIRST_FLAG)\n            break;\n\n        fputs(\".\", stdout);\n        fflush(stdout);\n        c_sleep(WAIT_TIME);\n    }\n\n    if (!(request_flags & FIRST_FLAG)) {\n        fputs(\"\\nfriends_test: The child took to long to respond!\\n\"\n              \"Friend requests may be broken, failing build!\\n\", stderr);\n        kill(child_pid, SIGKILL);\n        return -1;\n    }\n\n    return 0;\n}\n\nvoid child_got_request(Messenger *m, uint8_t *public_key, uint8_t *data, uint16_t length, void *userdata)\n{\n    fputs(\"OK\\nsending status to parent\", stdout);\n    fflush(stdout);\n    m_addfriend_norequest(m, public_key);\n    request_flags |= FIRST_FLAG;\n}\n\nvoid child_got_statuschange(Messenger *m, int friend_num, uint8_t *string, uint16_t length, void *userdata)\n{\n    request_flags |= SECOND_FLAG;\n}\n\nint parent_wait_for_message(DHT *dht)\n{\n    int i = 0;\n\n    fputs(\"Parent waiting for message.\", stdout);\n    fflush(stdout);\n\n    for (i = 0; i < WAIT_COUNT; i++) {\n        do_tox(dht);\n\n        if (request_flags & SECOND_FLAG)\n            break;\n\n        fputs(\".\", stdout);\n        fflush(stdout);\n        c_sleep(WAIT_TIME);\n    }\n\n    if (!(request_flags & SECOND_FLAG)) {\n        fputs(\"\\nParent hasn't received the message yet!\\n\"\n              \"Messaging may be broken, failing the build!\\n\", stderr);\n        kill(child_pid, SIGKILL);\n        return -1;\n    }\n\n    return 0;\n}\n\nvoid cleanup(void)\n{\n    munmap(parent_id, crypto_box_PUBLICKEYBYTES);\n    munmap(child_id, crypto_box_PUBLICKEYBYTES);\n    puts(\"============= END TEST =============\");\n}\n\nint main(int argc, char *argv[])\n{\n    puts(\"=========== FRIENDS_TEST ===========\");\n\n    /* set up the global memory */\n    parent_id = mmap(NULL, crypto_box_PUBLICKEYBYTES, PROT_READ | PROT_WRITE,\n                     MAP_SHARED | MAP_ANONYMOUS, -1, 0);\n    child_id = mmap(NULL, crypto_box_PUBLICKEYBYTES, PROT_READ | PROT_WRITE,\n                    MAP_SHARED | MAP_ANONYMOUS, -1, 0);\n\n    fputs(\"friends_test: Starting test...\\n\", stdout);\n\n    if ((child_pid = fork()) == 0) {\n        /* child */\n        int i = 0;\n        char *message = \"Y-yes Mr. Watson?\";\n\n        m = initMessenger();\n\n        Messenger_save(m, child_id);\n        msync(child_id, crypto_box_PUBLICKEYBYTES, MS_SYNC);\n\n        m_callback_friendrequest(m, child_got_request, NULL);\n        m_callback_statusmessage(m, child_got_statuschange, NULL);\n\n        /* wait on the friend request */\n        while (!(request_flags & FIRST_FLAG))\n            do_tox(m->dht);\n\n        /* wait for the status change */\n        while (!(request_flags & SECOND_FLAG))\n            do_tox(m->dht);\n\n        for (i = 0; i < 6; i++) {\n            /* send the message six times, just to be sure */\n            m_sendmessage(m, 0, (uint8_t *)message, strlen(message));\n            do_tox(m->dht);\n        }\n\n        cleanupMessenger(m);\n\n        return 0;\n    }\n\n    /* parent */\n    if (atexit(cleanup) != 0) {\n        fputs(\"friends_test: atexit() failed!\\nFailing build...\\n\", stderr);\n        kill(child_pid, SIGKILL);\n        return -1;\n    }\n\n    m = initMessenger();\n\n    msync(parent_id, crypto_box_PUBLICKEYBYTES, MS_SYNC);\n    m_callback_statusmessage(m, parent_confirm_status, NULL);\n    m_callback_friendmessage(m, parent_confirm_message, NULL);\n\n    /* hacky way to give the child time to set up */\n    c_sleep(50);\n\n    Messenger_save(m, parent_id);\n\n    if (parent_friend_request(m->dht) == -1)\n        return -1;\n\n    if (parent_wait_for_message(m->dht) == -1)\n        return -1;\n\n    wait(NULL);\n    fputs(\"friends_test: Build passed!\\n\", stdout);\n    return 0;\n}\n"
  },
  {
    "path": "auto_tests/helpers.h",
    "content": "#ifndef TOXCORE_TEST_HELPERS_H\n#define TOXCORE_TEST_HELPERS_H\n\n#include <check.h>\n\n#define DEFTESTCASE(NAME)                   \\\n    TCase *tc_##NAME = tcase_create(#NAME); \\\n    tcase_add_test(tc_##NAME, test_##NAME); \\\n    suite_add_tcase(s, tc_##NAME);\n\n#define DEFTESTCASE_SLOW(NAME, TIMEOUT) \\\n    DEFTESTCASE(NAME) \\\n    tcase_set_timeout(tc_##NAME, TIMEOUT);\n\n#endif // TOXCORE_TEST_HELPERS_H\n"
  },
  {
    "path": "auto_tests/messenger_test.c",
    "content": "/* unit tests for /core/Messenger.c\n *  Design:\n *      Just call every non-static function in Messenger.c, checking that\n *      they return as they should with check calls. \"Bad\" calls of the type\n *      function(bad_data, good_length) are _not_ checked for, this type\n *      of call is the fault of the client code.\n *\n *  Note:\n *      None of the functions here test things that rely on the network, i.e.\n *      checking that status changes are received, messages can be sent, etc.\n *      All of that is done in a separate test, with two local clients running. */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../testing/misc_tools.c\" // hex_string_to_bin\n#include \"../toxcore/Messenger.h\"\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n\n#include \"helpers.h\"\n\n#define REALLY_BIG_NUMBER ((1) << (sizeof(uint16_t) * 7))\n#define STRINGS_EQUAL(X, Y) (strcmp(X, Y) == 0)\n\nchar *friend_id_str = \"e4b3d5030bc99494605aecc33ceec8875640c1d74aa32790e821b17e98771c4a00000000f1db\";\n\n/* in case we need more than one ID for a test */\nchar *good_id_a_str = \"DB9B569D14850ED8364C3744CAC2C8FF78985D213E980C7C508D0E91E8E45441\";\nchar *good_id_b_str = \"d3f14b6d384d8f5f2a66cff637e69f28f539c5de61bc29744785291fa4ef4d64\";\n\nchar *bad_id_str =    \"9B569D14ff637e69f2\";\n\nunsigned char *friend_id = NULL;\nunsigned char *good_id_a = NULL;\nunsigned char *good_id_b = NULL;\nunsigned char *bad_id    = NULL;\n\nint friend_id_num = 0;\n\nMessenger *m;\n\nSTART_TEST(test_m_sendmesage)\n{\n    char *message = \"h-hi :3\";\n    int good_len = strlen(message);\n    int bad_len = MAX_CRYPTO_PACKET_SIZE;\n\n\n    ck_assert(m_send_message_generic(m, -1, MESSAGE_NORMAL, (uint8_t *)message, good_len, 0) == -1);\n    ck_assert(m_send_message_generic(m, REALLY_BIG_NUMBER, MESSAGE_NORMAL, (uint8_t *)message, good_len, 0) == -1);\n    ck_assert(m_send_message_generic(m, 17, MESSAGE_NORMAL, (uint8_t *)message, good_len, 0) == -1);\n    ck_assert(m_send_message_generic(m, friend_id_num, MESSAGE_NORMAL, (uint8_t *)message, bad_len, 0) == -2);\n}\nEND_TEST\n\nSTART_TEST(test_m_get_userstatus_size)\n{\n    int rc = 0;\n    ck_assert_msg((m_get_statusmessage_size(m, -1) == -1),\n                  \"m_get_statusmessage_size did NOT catch an argument of -1\");\n    ck_assert_msg((m_get_statusmessage_size(m, REALLY_BIG_NUMBER) == -1),\n                  \"m_get_statusmessage_size did NOT catch the following argument: %d\\n\",\n                  REALLY_BIG_NUMBER);\n    rc = m_get_statusmessage_size(m, friend_id_num);\n\n    /* this WILL error if the original m_addfriend_norequest() failed */\n    ck_assert_msg((rc >= 0 && rc <= MAX_STATUSMESSAGE_LENGTH),\n                  \"m_get_statusmessage_size is returning out of range values! (%i)\\n\"\n                  \"(this can be caused by the error of m_addfriend_norequest\"\n                  \" in the beginning of the suite)\\n\", rc);\n}\nEND_TEST\n\nSTART_TEST(test_m_set_userstatus)\n{\n    char *status = \"online!\";\n    uint16_t good_length = strlen(status);\n    uint16_t bad_length = REALLY_BIG_NUMBER;\n\n    ck_assert_msg((m_set_statusmessage(m, (uint8_t *)status, bad_length) == -1),\n                  \"m_set_userstatus did NOT catch the following length: %d\\n\",\n                  REALLY_BIG_NUMBER);\n\n    ck_assert_msg((m_set_statusmessage(m, (uint8_t *)status, good_length) == 0),\n                  \"m_set_userstatus did NOT return 0 on the following length: %d\\n\"\n                  \"MAX_STATUSMESSAGE_LENGTH: %d\\n\", good_length, MAX_STATUSMESSAGE_LENGTH);\n}\nEND_TEST\n\nSTART_TEST(test_m_get_friend_connectionstatus)\n{\n    ck_assert_msg((m_get_friend_connectionstatus(m, -1) == -1),\n                  \"m_get_friend_connectionstatus did NOT catch an argument of -1.\\n\");\n    ck_assert_msg((m_get_friend_connectionstatus(m, REALLY_BIG_NUMBER) == -1),\n                  \"m_get_friend_connectionstatus did NOT catch an argument of %d.\\n\",\n                  REALLY_BIG_NUMBER);\n}\nEND_TEST\n\nSTART_TEST(test_m_friend_exists)\n{\n    ck_assert_msg((m_friend_exists(m, -1) == 0),\n                  \"m_friend_exists did NOT catch an argument of -1.\\n\");\n    ck_assert_msg((m_friend_exists(m, REALLY_BIG_NUMBER) == 0),\n                  \"m_friend_exists did NOT catch an argument of %d.\\n\",\n                  REALLY_BIG_NUMBER);\n}\nEND_TEST\n\nSTART_TEST(test_m_delfriend)\n{\n    ck_assert_msg((m_delfriend(m, -1) == -1),\n                  \"m_delfriend did NOT catch an argument of -1\\n\");\n    ck_assert_msg((m_delfriend(m, REALLY_BIG_NUMBER) == -1),\n                  \"m_delfriend did NOT catch the following number: %d\\n\",\n                  REALLY_BIG_NUMBER);\n}\nEND_TEST\n/*\nSTART_TEST(test_m_addfriend)\n{\n    char *good_data = \"test\";\n    char *bad_data = \"\";\n\n    int good_len = strlen(good_data);\n    int bad_len = strlen(bad_data);\n    int really_bad_len = (MAX_CRYPTO_PACKET_SIZE - crypto_box_PUBLICKEYBYTES\n                     - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES\n                                      + crypto_box_ZEROBYTES + 100); */\n/* TODO: Update this properly to latest master\n    if(m_addfriend(m, (uint8_t *)friend_id, (uint8_t *)good_data, really_bad_len) != FAERR_TOOLONG)\n        ck_abort_msg(\"m_addfriend did NOT catch the following length: %d\\n\", really_bad_len);\n*/\n/* this will return an error if the original m_addfriend_norequest() failed */\n/*    if(m_addfriend(m, (uint8_t *)friend_id, (uint8_t *)good_data, good_len) != FAERR_ALREADYSENT)\n        ck_abort_msg(\"m_addfriend did NOT catch adding a friend we already have.\\n\"\n                     \"(this can be caused by the error of m_addfriend_norequest in\"\n                     \" the beginning of the suite)\\n\");\n\n    if(m_addfriend(m, (uint8_t *)good_id_b, (uint8_t *)bad_data, bad_len) != FAERR_NOMESSAGE)\n        ck_abort_msg(\"m_addfriend did NOT catch the following length: %d\\n\", bad_len);\n*/\n/* this should REALLY return an error */\n/*\n * TODO: validate client_id in m_addfriend?\nif(m_addfriend((uint8_t *)bad_id, (uint8_t *)good_data, good_len) >= 0)\n    ck_abort_msg(\"The following ID passed through \"\n          \"m_addfriend without an error:\\n'%s'\\n\", bad_id_str);\n\n}\nEND_TEST */\n\nSTART_TEST(test_setname)\n{\n    char *good_name = \"consensualCorn\";\n    int good_length = strlen(good_name);\n    int bad_length = REALLY_BIG_NUMBER;\n\n    ck_assert_msg((setname(m, (uint8_t *)good_name, bad_length) == -1),\n                  \"setname() did NOT error on %d as a length argument!\\n\", bad_length);\n\n    ck_assert_msg((setname(m, (uint8_t *)good_name, good_length) == 0),\n                  \"setname() did NOT return 0 on good arguments!\\n\");\n}\nEND_TEST\n\nSTART_TEST(test_getself_name)\n{\n    char *nickname = \"testGallop\";\n    int len = strlen(nickname);\n    char nick_check[len];\n\n    setname(m, (uint8_t *)nickname, len);\n    getself_name(m, (uint8_t *)nick_check);\n\n    ck_assert_msg((memcmp(nickname, nick_check, len) == 0),\n                  \"getself_name failed to return the known name!\\n\"\n                  \"known name: %s\\nreturned: %s\\n\", nickname, nick_check);\n}\nEND_TEST\n\n/* this test is excluded for now, due to lack of a way\n *  to set a friend's status for now.\n *  ideas:\n *      if we have access to the friends list, we could\n *      just add a status manually ourselves. */\n/*\nSTART_TEST(test_m_copy_userstatus)\n{\n    assert(m_copy_userstatus(-1, buf, MAX_USERSTATUS_LENGTH) == -1);\n    assert(m_copy_userstatus(REALLY_BIG_NUMBER, buf, MAX_USERSTATUS_LENGTH) == -1);\n    m_copy_userstatus(friend_id_num, buf, MAX_USERSTATUS_LENGTH + 6);\n\n    assert(STRINGS_EQUAL(name_buf, friend_id_status));\n}\nEND_TEST\n*/\n\nSTART_TEST(test_getname)\n{\n    uint8_t name_buf[MAX_NAME_LENGTH];\n    uint8_t test_name[] = {'f', 'o', 'o'};\n\n    ck_assert(getname(m, -1, name_buf) == -1);\n    ck_assert(getname(m, REALLY_BIG_NUMBER, name_buf) == -1);\n\n    memcpy(m->friendlist[0].name, &test_name[0], 3);\n    m->friendlist[0].name_length = 4;\n    ck_assert(getname(m, 0, &name_buf[0]) == 4);\n\n    ck_assert(strcmp((char *)&name_buf[0], \"foo\") == 0);\n}\nEND_TEST\n\nSTART_TEST(test_dht_state_saveloadsave)\n{\n    /* validate that:\n     * a) saving stays within the confined space\n     * b) a save()d state can be load()ed back successfully\n     * c) a second save() is of equal size\n     * d) the second save() is of equal content */\n    size_t i, extra = 64;\n    size_t size = DHT_size(m->dht);\n    uint8_t buffer[size + 2 * extra];\n    memset(buffer, 0xCD, extra);\n    memset(buffer + extra + size, 0xCD, extra);\n    DHT_save(m->dht, buffer + extra);\n\n    for (i = 0; i < extra; i++) {\n        ck_assert_msg(buffer[i] == 0xCD, \"Buffer underwritten from DHT_save() @%u\", i);\n        ck_assert_msg(buffer[extra + size + i] == 0xCD, \"Buffer overwritten from DHT_save() @%u\", i);\n    }\n\n    int res = DHT_load(m->dht, buffer + extra, size);\n\n    if (res == -1)\n        ck_assert_msg(res == 0, \"Failed to load back stored buffer: res == -1\");\n    else {\n        char msg[128];\n        size_t offset = res >> 4;\n        uint8_t *ptr = buffer + extra + offset;\n        sprintf(msg, \"Failed to load back stored buffer: 0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx @%zu/%zu, code %d\",\n                ptr[-2], ptr[-1], ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], offset, size, res & 0x0F);\n        ck_assert_msg(res == 0, msg);\n    }\n\n    size_t size2 = DHT_size(m->dht);\n    ck_assert_msg(size == size2, \"Messenger \\\"grew\\\" in size from a store/load cycle: %u -> %u\", size, size2);\n\n    uint8_t buffer2[size2];\n    DHT_save(m->dht, buffer2);\n\n    ck_assert_msg(!memcmp(buffer + extra, buffer2, size), \"DHT state changed by store/load/store cycle\");\n}\nEND_TEST\n\nSTART_TEST(test_messenger_state_saveloadsave)\n{\n    /* validate that:\n     * a) saving stays within the confined space\n     * b) a save()d state can be load()ed back successfully\n     * c) a second save() is of equal size\n     * d) the second save() is of equal content */\n    size_t i, extra = 64;\n    size_t size = messenger_size(m);\n    uint8_t buffer[size + 2 * extra];\n    memset(buffer, 0xCD, extra);\n    memset(buffer + extra + size, 0xCD, extra);\n    messenger_save(m, buffer + extra);\n\n    for (i = 0; i < extra; i++) {\n        ck_assert_msg(buffer[i] == 0xCD, \"Buffer underwritten from messenger_save() @%u\", i);\n        ck_assert_msg(buffer[extra + size + i] == 0xCD, \"Buffer overwritten from messenger_save() @%u\", i);\n    }\n\n    int res = messenger_load(m, buffer + extra, size);\n\n    if (res == -1)\n        ck_assert_msg(res == 0, \"Failed to load back stored buffer: res == -1\");\n    else {\n        char msg[128];\n        size_t offset = res >> 4;\n        uint8_t *ptr = buffer + extra + offset;\n        sprintf(msg, \"Failed to load back stored buffer: 0x%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx @%zu/%zu, code %d\",\n                ptr[-2], ptr[-1], ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], offset, size, res & 0x0F);\n        ck_assert_msg(res == 0, msg);\n    }\n\n    size_t size2 = messenger_size(m);\n    ck_assert_msg(size == size2, \"Messenger \\\"grew\\\" in size from a store/load cycle: %u -> %u\", size, size2);\n\n    uint8_t buffer2[size2];\n    messenger_save(m, buffer2);\n\n    ck_assert_msg(!memcmp(buffer + extra, buffer2, size), \"Messenger state changed by store/load/store cycle\");\n}\nEND_TEST\n\nSuite *messenger_suite(void)\n{\n    Suite *s = suite_create(\"Messenger\");\n\n    DEFTESTCASE(dht_state_saveloadsave);\n    DEFTESTCASE(messenger_state_saveloadsave);\n\n    DEFTESTCASE(getself_name);\n    DEFTESTCASE(m_get_userstatus_size);\n    DEFTESTCASE(m_set_userstatus);\n\n    /* DEFTESTCASE(m_addfriend); */\n    DEFTESTCASE(m_friend_exists);\n    DEFTESTCASE(m_get_friend_connectionstatus);\n    DEFTESTCASE(m_delfriend);\n\n    DEFTESTCASE(setname);\n    DEFTESTCASE(getname);\n    DEFTESTCASE(m_sendmesage);\n\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    Suite *messenger = messenger_suite();\n    SRunner *test_runner = srunner_create(messenger);\n    int number_failed = 0;\n\n    friend_id = hex_string_to_bin(friend_id_str);\n    good_id_a = hex_string_to_bin(good_id_a_str);\n    good_id_b = hex_string_to_bin(good_id_b_str);\n    bad_id    = hex_string_to_bin(bad_id_str);\n\n    /* IPv6 status from global define */\n    Messenger_Options options = {0};\n    options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT;\n    m = new_messenger(&options, 0);\n\n    /* setup a default friend and friendnum */\n    if (m_addfriend_norequest(m, (uint8_t *)friend_id) < 0)\n        fputs(\"m_addfriend_norequest() failed on a valid ID!\\n\"\n              \"this was CRITICAL to the test, and the build WILL fail.\\n\"\n              \"the tests will continue now...\\n\\n\", stderr);\n\n    if ((friend_id_num = getfriend_id(m, (uint8_t *)friend_id)) < 0)\n        fputs(\"getfriend_id() failed on a valid ID!\\n\"\n              \"this was CRITICAL to the test, and the build WILL fail.\\n\"\n              \"the tests will continue now...\\n\\n\", stderr);\n\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n    free(friend_id);\n    free(good_id_a);\n    free(good_id_b);\n    free(bad_id);\n\n    kill_messenger(m);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/network_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"../toxcore/network.h\"\n\n#include \"helpers.h\"\n\nSTART_TEST(test_addr_resolv_localhost)\n{\n#ifdef __CYGWIN__\n    /* force initialization of network stack\n     * normally this should happen automatically\n     * cygwin doesn't do it for every network related function though\n     * e.g. not for getaddrinfo... */\n    socket(0, 0, 0);\n    errno = 0;\n#endif\n\n    const char localhost[] = \"localhost\";\n    int localhost_split = 0;\n\n    IP ip;\n    ip_init(&ip, 0); // ipv6enabled = 0\n\n    int res = addr_resolve(localhost, &ip, NULL);\n\n    ck_assert_msg(res > 0, \"Resolver failed: %u, %s (%x, %x)\", errno, strerror(errno));\n\n    if (res > 0) {\n        ck_assert_msg(ip.family == AF_INET, \"Expected family AF_INET, got %u.\", ip.family);\n        ck_assert_msg(ip.ip4.uint32 == htonl(0x7F000001), \"Expected 127.0.0.1, got %s.\", inet_ntoa(ip.ip4.in_addr));\n    }\n\n    ip_init(&ip, 1); // ipv6enabled = 1\n    res = addr_resolve(localhost, &ip, NULL);\n\n    if (!(res & TOX_ADDR_RESOLVE_INET6)) {\n        res = addr_resolve(\"ip6-localhost\", &ip, NULL);\n        localhost_split = 1;\n    }\n\n    ck_assert_msg(res > 0, \"Resolver failed: %u, %s (%x, %x)\", errno, strerror(errno));\n\n    if (res > 0) {\n        ck_assert_msg(ip.family == AF_INET6, \"Expected family AF_INET6 (%u), got %u.\", AF_INET6, ip.family);\n        ck_assert_msg(!memcmp(&ip.ip6, &in6addr_loopback, sizeof(IP6)), \"Expected ::1, got %s.\", ip_ntoa(&ip));\n    }\n\n    if (!localhost_split) {\n        ip_init(&ip, 1); // ipv6enabled = 1\n        ip.family = AF_UNSPEC;\n        IP extra;\n        ip_reset(&extra);\n        res = addr_resolve(localhost, &ip, &extra);\n        ck_assert_msg(res > 0, \"Resolver failed: %u, %s (%x, %x)\", errno, strerror(errno));\n\n        if (res > 0) {\n            ck_assert_msg(ip.family == AF_INET6, \"Expected family AF_INET6 (%u), got %u.\", AF_INET6, ip.family);\n            ck_assert_msg(!memcmp(&ip.ip6, &in6addr_loopback, sizeof(IP6)), \"Expected ::1, got %s.\", ip_ntoa(&ip));\n\n            ck_assert_msg(extra.family == AF_INET, \"Expected family AF_INET (%u), got %u.\", AF_INET, extra.family);\n            ck_assert_msg(extra.ip4.uint32 == htonl(0x7F000001), \"Expected 127.0.0.1, got %s.\", inet_ntoa(extra.ip4.in_addr));\n        }\n    } else {\n        printf(\"Localhost seems to be split in two.\\n\");\n    }\n}\nEND_TEST\n\nSTART_TEST(test_ip_equal)\n{\n    int res;\n    IP ip1, ip2;\n    ip_reset(&ip1);\n    ip_reset(&ip2);\n\n    res = ip_equal(NULL, NULL);\n    ck_assert_msg(res == 0, \"ip_equal(NULL, NULL): expected result 0, got %u.\", res);\n\n    res = ip_equal(&ip1, NULL);\n    ck_assert_msg(res == 0, \"ip_equal(PTR, NULL): expected result 0, got %u.\", res);\n\n    res = ip_equal(NULL, &ip1);\n    ck_assert_msg(res == 0, \"ip_equal(NULL, PTR): expected result 0, got %u.\", res);\n\n    ip1.family = AF_INET;\n    ip1.ip4.uint32 = htonl(0x7F000001);\n\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res == 0, \"ip_equal( {AF_INET, 127.0.0.1}, {AF_UNSPEC, 0} ): expected result 0, got %u.\", res);\n\n    ip2.family = AF_INET;\n    ip2.ip4.uint32 = htonl(0x7F000001);\n\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res != 0, \"ip_equal( {AF_INET, 127.0.0.1}, {AF_INET, 127.0.0.1} ): expected result != 0, got 0.\");\n\n    ip2.ip4.uint32 = htonl(0x7F000002);\n\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res == 0, \"ip_equal( {AF_INET, 127.0.0.1}, {AF_INET, 127.0.0.2} ): expected result 0, got %u.\", res);\n\n    ip2.family = AF_INET6;\n    ip2.ip6.uint32[0] = 0;\n    ip2.ip6.uint32[1] = 0;\n    ip2.ip6.uint32[2] = htonl(0xFFFF);\n    ip2.ip6.uint32[3] = htonl(0x7F000001);\n\n    ck_assert_msg(IN6_IS_ADDR_V4MAPPED(&ip2.ip6.in6_addr) != 0,\n                  \"IN6_IS_ADDR_V4MAPPED(::ffff:127.0.0.1): expected != 0, got 0.\");\n\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res != 0, \"ip_equal( {AF_INET, 127.0.0.1}, {AF_INET6, ::ffff:127.0.0.1} ): expected result != 0, got 0.\");\n\n    memcpy(&ip2.ip6, &in6addr_loopback, sizeof(IP6));\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res == 0, \"ip_equal( {AF_INET, 127.0.0.1}, {AF_INET6, ::1} ): expected result 0, got %u.\", res);\n\n    memcpy(&ip1, &ip2, sizeof(IP));\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res != 0, \"ip_equal( {AF_INET6, ::1}, {AF_INET6, ::1} ): expected result != 0, got 0.\");\n\n    ip2.ip6.uint8[15]++;\n    res = ip_equal(&ip1, &ip2);\n    ck_assert_msg(res == 0, \"ip_equal( {AF_INET6, ::1}, {AF_INET6, ::2} ): expected result 0, got %res.\", res);\n}\nEND_TEST\n\nSuite *network_suite(void)\n{\n    Suite *s = suite_create(\"Network\");\n\n    DEFTESTCASE(addr_resolv_localhost);\n    DEFTESTCASE(ip_equal);\n\n    return s;\n}\n\nint main()\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *network = network_suite();\n    SRunner *test_runner = srunner_create(network);\n    int number_failed = 0;\n\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/onion_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"../toxcore/onion.h\"\n#include \"../toxcore/onion_announce.h\"\n#include \"../toxcore/onion_client.h\"\n#include \"../toxcore/util.h\"\n\n#include \"helpers.h\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\nvoid do_onion(Onion *onion)\n{\n    networking_poll(onion->net);\n    do_DHT(onion->dht);\n}\n\nstatic int handled_test_1;\nstatic int handle_test_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (memcmp(packet, \"\\x83 Install Gentoo\", sizeof(\"\\x83 Install Gentoo\")) != 0)\n        return 1;\n\n    if (send_onion_response(onion->net, source, (uint8_t *)\"\\x84 install gentoo\", sizeof(\"\\x84 install gentoo\"),\n                            packet + sizeof(\"\\x83 Install Gentoo\")) == -1)\n        return 1;\n\n    handled_test_1 = 1;\n    return 0;\n}\n\nstatic int handled_test_2;\nstatic int handle_test_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    if (length != sizeof(\"\\x84 install Gentoo\"))\n        return 1;\n\n    if (memcmp(packet, (uint8_t *)\"\\x84 install gentoo\", sizeof(\"\\x84 install gentoo\")) != 0)\n        return 1;\n\n    handled_test_2 = 1;\n    return 0;\n}\n/*\nvoid print_client_id(uint8_t *client_id, uint32_t length)\n{\n    uint32_t j;\n\n    for (j = 0; j < length; j++) {\n        printf(\"%02hhX\", client_id[j]);\n    }\n    printf(\"\\n\");\n}\n*/\nuint8_t sb_data[ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];\nstatic int handled_test_3;\nuint8_t test_3_pub_key[crypto_box_PUBLICKEYBYTES];\nuint8_t test_3_ping_id[crypto_hash_sha256_BYTES];\nstatic int handle_test_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length != (1 + crypto_box_NONCEBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + 1 + crypto_hash_sha256_BYTES +\n                   crypto_box_MACBYTES))\n        return 1;\n\n    uint8_t plain[1 + crypto_hash_sha256_BYTES];\n    //print_client_id(packet, length);\n    int len = decrypt_data(test_3_pub_key, onion->dht->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,\n                           packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES,\n                           1 + crypto_hash_sha256_BYTES + crypto_box_MACBYTES, plain);\n\n    if (len == -1)\n        return 1;\n\n\n    if (memcmp(packet + 1, sb_data, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH) != 0)\n        return 1;\n\n    memcpy(test_3_ping_id, plain + 1, crypto_hash_sha256_BYTES);\n    //print_client_id(test_3_ping_id, sizeof(test_3_ping_id));\n    handled_test_3 = 1;\n    return 0;\n}\n\nuint8_t nonce[crypto_box_NONCEBYTES];\nstatic int handled_test_4;\nstatic int handle_test_4(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length != (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + sizeof(\"Install gentoo\") + crypto_box_MACBYTES))\n        return 1;\n\n    uint8_t plain[sizeof(\"Install gentoo\")] = {0};\n\n    if (memcmp(nonce, packet + 1, crypto_box_NONCEBYTES) != 0)\n        return 1;\n\n    int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1,\n                           packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, sizeof(\"Install gentoo\") + crypto_box_MACBYTES, plain);\n\n    if (len == -1)\n        return 1;\n\n    if (memcmp(plain, \"Install gentoo\", sizeof(\"Install gentoo\")) != 0)\n        return 1;\n\n    handled_test_4 = 1;\n    return 0;\n}\n\nSTART_TEST(test_basic)\n{\n    IP ip;\n    ip_init(&ip, 1);\n    ip.ip6.uint8[15] = 1;\n    Onion *onion1 = new_onion(new_DHT(new_networking(ip, 34567)));\n    Onion *onion2 = new_onion(new_DHT(new_networking(ip, 34568)));\n    ck_assert_msg((onion1 != NULL) && (onion2 != NULL), \"Onion failed initializing.\");\n    networking_registerhandler(onion2->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_test_1, onion2);\n\n    IP_Port on1 = {ip, onion1->net->port};\n    Node_format n1;\n    memcpy(n1.public_key, onion1->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    n1.ip_port = on1;\n\n    IP_Port on2 = {ip, onion2->net->port};\n    Node_format n2;\n    memcpy(n2.public_key, onion2->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    n2.ip_port = on2;\n\n    Node_format nodes[4];\n    nodes[0] = n1;\n    nodes[1] = n2;\n    nodes[2] = n1;\n    nodes[3] = n2;\n    Onion_Path path;\n    create_onion_path(onion1->dht, &path, nodes);\n    int ret = send_onion_packet(onion1->net, &path, nodes[3].ip_port, (uint8_t *)\"\\x83 Install Gentoo\",\n                                sizeof(\"\\x83 Install Gentoo\"));\n    ck_assert_msg(ret == 0, \"Failed to create/send onion packet.\");\n\n    handled_test_1 = 0;\n\n    while (handled_test_1 == 0) {\n        do_onion(onion1);\n        do_onion(onion2);\n    }\n\n    networking_registerhandler(onion1->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_test_2, onion1);\n    handled_test_2 = 0;\n\n    while (handled_test_2 == 0) {\n        do_onion(onion1);\n        do_onion(onion2);\n    }\n\n    Onion_Announce *onion1_a = new_onion_announce(onion1->dht);\n    Onion_Announce *onion2_a = new_onion_announce(onion2->dht);\n    networking_registerhandler(onion1->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_test_3, onion1);\n    ck_assert_msg((onion1_a != NULL) && (onion2_a != NULL), \"Onion_Announce failed initializing.\");\n    uint8_t zeroes[64] = {0};\n    randombytes(sb_data, sizeof(sb_data));\n    uint64_t s;\n    memcpy(&s, sb_data, sizeof(uint64_t));\n    memcpy(test_3_pub_key, nodes[3].public_key, crypto_box_PUBLICKEYBYTES);\n    ret = send_announce_request(onion1->net, &path, nodes[3], onion1->dht->self_public_key,\n                                onion1->dht->self_secret_key,\n                                zeroes, onion1->dht->self_public_key, onion1->dht->self_public_key, s);\n    ck_assert_msg(ret == 0, \"Failed to create/send onion announce_request packet.\");\n    handled_test_3 = 0;\n\n    while (handled_test_3 == 0) {\n        do_onion(onion1);\n        do_onion(onion2);\n        c_sleep(50);\n    }\n\n    randombytes(sb_data, sizeof(sb_data));\n    memcpy(&s, sb_data, sizeof(uint64_t));\n    memcpy(onion2_a->entries[1].public_key, onion2->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    onion2_a->entries[1].time = unix_time();\n    networking_registerhandler(onion1->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_test_4, onion1);\n    send_announce_request(onion1->net, &path, nodes[3], onion1->dht->self_public_key, onion1->dht->self_secret_key,\n                          test_3_ping_id, onion1->dht->self_public_key, onion1->dht->self_public_key, s);\n\n    while (memcmp(onion2_a->entries[ONION_ANNOUNCE_MAX_ENTRIES - 2].public_key, onion1->dht->self_public_key,\n                  crypto_box_PUBLICKEYBYTES) != 0) {\n        do_onion(onion1);\n        do_onion(onion2);\n        c_sleep(50);\n    }\n\n    c_sleep(1000);\n    Onion *onion3 = new_onion(new_DHT(new_networking(ip, 34569)));\n    ck_assert_msg((onion3 != NULL), \"Onion failed initializing.\");\n\n    new_nonce(nonce);\n    ret = send_data_request(onion3->net, &path, nodes[3].ip_port, onion1->dht->self_public_key,\n                            onion1->dht->self_public_key,\n                            nonce, (uint8_t *)\"Install gentoo\", sizeof(\"Install gentoo\"));\n    ck_assert_msg(ret == 0, \"Failed to create/send onion data_request packet.\");\n    handled_test_4 = 0;\n\n    while (handled_test_4 == 0) {\n        do_onion(onion1);\n        do_onion(onion2);\n        c_sleep(50);\n    }\n\n    kill_onion_announce(onion1_a);\n    kill_onion_announce(onion2_a);\n\n    {\n        Onion *onion = onion1;\n\n        Networking_Core *net = onion->dht->net;\n        DHT *dht = onion->dht;\n        kill_onion(onion);\n        kill_DHT(dht);\n        kill_networking(net);\n    }\n\n    {\n        Onion *onion = onion2;\n\n        Networking_Core *net = onion->dht->net;\n        DHT *dht = onion->dht;\n        kill_onion(onion);\n        kill_DHT(dht);\n        kill_networking(net);\n    }\n\n    {\n        Onion *onion = onion3;\n\n        Networking_Core *net = onion->dht->net;\n        DHT *dht = onion->dht;\n        kill_onion(onion);\n        kill_DHT(dht);\n        kill_networking(net);\n    }\n}\nEND_TEST\n\ntypedef struct {\n    Onion *onion;\n    Onion_Announce *onion_a;\n    Onion_Client *onion_c;\n} Onions;\n\nOnions *new_onions(uint16_t port)\n{\n    IP ip;\n    ip_init(&ip, 1);\n    ip.ip6.uint8[15] = 1;\n    Onions *on = malloc(sizeof(Onions));\n    DHT *dht = new_DHT(new_networking(ip, port));\n    on->onion = new_onion(dht);\n    on->onion_a = new_onion_announce(dht);\n    TCP_Proxy_Info inf = {0};\n    on->onion_c = new_onion_client(new_net_crypto(dht, &inf));\n\n    if (on->onion && on->onion_a && on->onion_c)\n        return on;\n\n    return NULL;\n}\n\nvoid do_onions(Onions *on)\n{\n    networking_poll(on->onion->net);\n    do_DHT(on->onion->dht);\n    do_onion_client(on->onion_c);\n}\n\nvoid kill_onions(Onions *on)\n{\n    Networking_Core *net = on->onion->dht->net;\n    DHT *dht = on->onion->dht;\n    Net_Crypto *c = on->onion_c->c;\n    kill_onion_client(on->onion_c);\n    kill_onion_announce(on->onion_a);\n    kill_onion(on->onion);\n    kill_net_crypto(c);\n    kill_DHT(dht);\n    kill_networking(net);\n    free(on);\n}\n\n#define NUM_ONIONS 50\n#define NUM_FIRST 7\n#define NUM_LAST 37\n\n_Bool first_ip, last_ip;\nvoid dht_ip_callback(void *object, int32_t number, IP_Port ip_port)\n{\n    if (NUM_FIRST == number) {\n        first_ip = 1;\n        return;\n    }\n\n    if (NUM_LAST == number) {\n        last_ip = 1;\n        return;\n    }\n\n    ck_abort_msg(\"Error.\");\n}\n\n_Bool first, last;\nuint8_t first_dht_pk[crypto_box_PUBLICKEYBYTES];\nuint8_t last_dht_pk[crypto_box_PUBLICKEYBYTES];\n\nstatic void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key)\n{\n    if ((NUM_FIRST == number && !first) || (NUM_LAST == number && !last)) {\n        Onions *on = object;\n        uint16_t count = 0;\n        int ret = DHT_addfriend(on->onion->dht, dht_public_key, &dht_ip_callback, object, number, &count);\n        ck_assert_msg(ret == 0, \"DHT_addfriend() did not return 0\");\n        ck_assert_msg(count == 1, \"Count not 1, count is %u\", count);\n\n        if (NUM_FIRST == number && !first) {\n            first = 1;\n\n            if (memcmp(dht_public_key, last_dht_pk, crypto_box_PUBLICKEYBYTES) != 0) {\n                ck_abort_msg(\"Error wrong dht key.\");\n            }\n\n            return;\n        }\n\n        if (NUM_LAST == number && !last) {\n            last = 1;\n\n            if (memcmp(dht_public_key, first_dht_pk, crypto_box_PUBLICKEYBYTES) != 0) {\n                ck_abort_msg(\"Error wrong dht key.\");\n            }\n\n            return;\n        }\n\n        ck_abort_msg(\"Error.\");\n    }\n}\n\nSTART_TEST(test_announce)\n{\n    uint32_t i, j;\n    Onions *onions[NUM_ONIONS];\n\n    for (i = 0; i < NUM_ONIONS; ++i) {\n        onions[i] = new_onions(i + 34655);\n        ck_assert_msg(onions[i] != 0, \"Failed to create onions. %u\");\n    }\n\n    IP ip;\n    ip_init(&ip, 1);\n    ip.ip6.uint8[15] = 1;\n\n    for (i = 3; i < NUM_ONIONS; ++i) {\n        IP_Port ip_port = {ip, onions[i - 1]->onion->net->port};\n        DHT_bootstrap(onions[i]->onion->dht, ip_port, onions[i - 1]->onion->dht->self_public_key);\n        IP_Port ip_port1 = {ip, onions[i - 2]->onion->net->port};\n        DHT_bootstrap(onions[i]->onion->dht, ip_port1, onions[i - 2]->onion->dht->self_public_key);\n        IP_Port ip_port2 = {ip, onions[i - 3]->onion->net->port};\n        DHT_bootstrap(onions[i]->onion->dht, ip_port2, onions[i - 3]->onion->dht->self_public_key);\n    }\n\n    uint32_t connected = 0;\n\n    while (connected != NUM_ONIONS) {\n        connected = 0;\n\n        for (i = 0; i < NUM_ONIONS; ++i) {\n            do_onions(onions[i]);\n            connected += DHT_isconnected(onions[i]->onion->dht);\n        }\n\n        c_sleep(50);\n    }\n\n    printf(\"connected\\n\");\n\n    for (i = 0; i < 25 * 2; ++i) {\n        for (j = 0; j < NUM_ONIONS; ++j) {\n            do_onions(onions[j]);\n        }\n\n        c_sleep(50);\n    }\n\n    memcpy(first_dht_pk, onions[NUM_FIRST]->onion->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(last_dht_pk, onions[NUM_LAST]->onion->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n\n    printf(\"adding friend\\n\");\n    int frnum_f = onion_addfriend(onions[NUM_FIRST]->onion_c, onions[NUM_LAST]->onion_c->c->self_public_key);\n    int frnum = onion_addfriend(onions[NUM_LAST]->onion_c, onions[NUM_FIRST]->onion_c->c->self_public_key);\n\n    onion_dht_pk_callback(onions[NUM_FIRST]->onion_c, frnum_f, &dht_pk_callback, onions[NUM_FIRST], NUM_FIRST);\n    onion_dht_pk_callback(onions[NUM_LAST]->onion_c, frnum, &dht_pk_callback, onions[NUM_LAST], NUM_LAST);\n\n    int ok = -1;\n\n    IP_Port ip_port;\n\n    while (!first || !last) {\n        for (i = 0; i < NUM_ONIONS; ++i) {\n            do_onions(onions[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    printf(\"Waiting for ips\\n\");\n\n    while (!first_ip || !last_ip) {\n        for (i = 0; i < NUM_ONIONS; ++i) {\n            do_onions(onions[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    onion_getfriendip(onions[NUM_LAST]->onion_c, frnum, &ip_port);\n    ck_assert_msg(ip_port.port == onions[NUM_FIRST]->onion->net->port, \"Port in returned ip not correct.\");\n\n    for (i = 0; i < NUM_ONIONS; ++i) {\n        kill_onions(onions[i]);\n    }\n}\nEND_TEST\n\nSuite *onion_suite(void)\n{\n    Suite *s = suite_create(\"Onion\");\n\n    DEFTESTCASE_SLOW(basic, 5);\n    DEFTESTCASE_SLOW(announce, 70);\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *onion = onion_suite();\n    SRunner *test_runner = srunner_create(onion);\n\n    int number_failed = 0;\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n"
  },
  {
    "path": "auto_tests/skeleton_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"helpers.h\"\n\n/*\n#include \"../<stuff to test>\"\n*/\n\nSTART_TEST(test_creativetestnamegoeshere)\n{\n    uint8_t test = 0;\n    ck_assert_msg(test == 0, \"test: expected result 0, got %u.\", test);\n}\nEND_TEST\n\nSuite *creativesuitenamegoeshere_suite(void)\n{\n    Suite *s = suite_create(\"creativesuitedescritptiongoeshere\");\n\n    DEFTESTCASE(/* remove test_ from test function names */ creativetestnamegoeshere);\n\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *creativesuitenamegoeshere = creativesuitenamegoeshere_suite();\n    SRunner *test_runner = srunner_create(creativesuitenamegoeshere);\n\n    int number_failed = 0;\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n\n"
  },
  {
    "path": "auto_tests/tox_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <stdio.h>\n#include <check.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include \"../toxcore/tox.h\"\n\n#include \"helpers.h\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n\nvoid accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    if (length == 7 && memcmp(\"Gentoo\", data, 7) == 0) {\n        tox_friend_add_norequest(m, public_key, 0);\n    }\n}\nuint32_t messages_received;\n\nvoid print_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,\n                   void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    if (type != TOX_MESSAGE_TYPE_NORMAL) {\n        ck_abort_msg(\"Bad type\");\n    }\n\n    uint8_t cmp_msg[TOX_MAX_MESSAGE_LENGTH];\n    memset(cmp_msg, 'G', sizeof(cmp_msg));\n\n    if (length == TOX_MAX_MESSAGE_LENGTH && memcmp(string, cmp_msg, sizeof(cmp_msg)) == 0)\n        ++messages_received;\n}\n\nuint32_t name_changes;\n\nvoid print_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    if (length == sizeof(\"Gentoo\") && memcmp(string, \"Gentoo\", sizeof(\"Gentoo\")) == 0)\n        ++name_changes;\n}\n\nuint32_t status_m_changes;\nvoid print_status_m_change(Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length, void *user_data)\n{\n    if (*((uint32_t *)user_data) != 974536)\n        return;\n\n    if (length == sizeof(\"Installing Gentoo\") && memcmp(message, \"Installing Gentoo\", sizeof(\"Installing Gentoo\")) == 0)\n        ++status_m_changes;\n}\n\nuint32_t typing_changes;\n\nvoid print_typingchange(Tox *m, uint32_t friendnumber, bool typing, void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    if (!typing)\n        typing_changes = 1;\n    else\n        typing_changes = 2;\n}\n\nuint32_t custom_packet;\n\nvoid handle_custom_packet(Tox *m, uint32_t friend_num, const uint8_t *data, size_t len, void *object)\n{\n    uint8_t number = *((uint32_t *)object);\n\n    if (len != TOX_MAX_CUSTOM_PACKET_SIZE)\n        return;\n\n    uint8_t f_data[len];\n    memset(f_data, number, len);\n\n    if (memcmp(f_data, data, len) == 0) {\n        ++custom_packet;\n    } else {\n        ck_abort_msg(\"Custom packet fail. %u\", number);\n    }\n\n    return;\n}\n\nuint64_t size_recv;\nuint64_t sending_pos;\n\nuint8_t file_cmp_id[TOX_FILE_ID_LENGTH];\nuint8_t filenum;\nuint32_t file_accepted;\nuint64_t file_size;\nvoid tox_file_receive(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t filesize,\n                      const uint8_t *filename, size_t filename_length, void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    if (kind != TOX_FILE_KIND_DATA) {\n        ck_abort_msg(\"Bad kind\");\n        return;\n    }\n\n    if (!(filename_length == sizeof(\"Gentoo.exe\") && memcmp(filename, \"Gentoo.exe\", sizeof(\"Gentoo.exe\")) == 0)) {\n        ck_abort_msg(\"Bad filename\");\n        return;\n    }\n\n    uint8_t file_id[TOX_FILE_ID_LENGTH];\n\n    if (!tox_file_get_file_id(tox, friend_number, file_number, file_id, 0)) {\n        ck_abort_msg(\"tox_file_get_file_id error\");\n    }\n\n    if (memcmp(file_id, file_cmp_id, TOX_FILE_ID_LENGTH) != 0) {\n        ck_abort_msg(\"bad file_id\");\n    }\n\n    uint8_t empty[TOX_FILE_ID_LENGTH] = {0};\n\n    if (memcmp(empty, file_cmp_id, TOX_FILE_ID_LENGTH) == 0) {\n        ck_abort_msg(\"empty file_id\");\n    }\n\n    file_size = filesize;\n\n    if (filesize) {\n        sending_pos = size_recv = 1337;\n\n        TOX_ERR_FILE_SEEK err_s;\n\n        if (!tox_file_seek(tox, friend_number, file_number, 1337, &err_s)) {\n            ck_abort_msg(\"tox_file_seek error\");\n        }\n\n        ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_OK, \"tox_file_seek wrong error\");\n    } else {\n        sending_pos = size_recv = 0;\n    }\n\n    TOX_ERR_FILE_CONTROL error;\n\n    if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, &error)) {\n        ++file_accepted;\n    } else {\n        ck_abort_msg(\"tox_file_control failed. %i\", error);\n    }\n\n    TOX_ERR_FILE_SEEK err_s;\n\n    if (tox_file_seek(tox, friend_number, file_number, 1234, &err_s)) {\n        ck_abort_msg(\"tox_file_seek no error\");\n    }\n\n    ck_assert_msg(err_s == TOX_ERR_FILE_SEEK_DENIED, \"tox_file_seek wrong error\");\n}\n\nuint32_t sendf_ok;\nvoid file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,\n                        void *userdata)\n{\n    if (*((uint32_t *)userdata) != 974536)\n        return;\n\n    /* First send file num is 0.*/\n    if (file_number == 0 && control == TOX_FILE_CONTROL_RESUME)\n        sendf_ok = 1;\n}\n\nuint64_t max_sending;\n_Bool m_send_reached;\nuint8_t sending_num;\n_Bool file_sending_done;\nvoid tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length,\n                            void *user_data)\n{\n    if (*((uint32_t *)user_data) != 974536)\n        return;\n\n    if (!sendf_ok) {\n        ck_abort_msg(\"Didn't get resume control\");\n    }\n\n    if (sending_pos != position) {\n        ck_abort_msg(\"Bad position %llu\", position);\n        return;\n    }\n\n    if (length == 0) {\n        if (file_sending_done) {\n            ck_abort_msg(\"File sending already done.\");\n        }\n\n        file_sending_done = 1;\n        return;\n    }\n\n    if (position + length > max_sending) {\n        if (m_send_reached) {\n            ck_abort_msg(\"Requested done file tranfer.\");\n        }\n\n        length = max_sending - position;\n        m_send_reached = 1;\n    }\n\n    TOX_ERR_FILE_SEND_CHUNK error;\n    uint8_t f_data[length];\n    memset(f_data, sending_num, length);\n\n    if (tox_file_send_chunk(tox, friend_number, file_number, position, f_data, length, &error)) {\n        ++sending_num;\n        sending_pos += length;\n    } else {\n        ck_abort_msg(\"Could not send chunk %i\", error);\n    }\n\n    if (error != TOX_ERR_FILE_SEND_CHUNK_OK) {\n        ck_abort_msg(\"Wrong error code\");\n    }\n}\n\n\nuint8_t num;\n_Bool file_recv;\nvoid write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,\n                size_t length, void *user_data)\n{\n    if (*((uint32_t *)user_data) != 974536)\n        return;\n\n    if (size_recv != position) {\n        ck_abort_msg(\"Bad position\");\n        return;\n    }\n\n    if (length == 0) {\n        file_recv = 1;\n        return;\n    }\n\n    uint8_t f_data[length];\n    memset(f_data, num, length);\n    ++num;\n\n    if (memcmp(f_data, data, length) == 0) {\n        size_recv += length;\n    } else {\n        ck_abort_msg(\"FILE_CORRUPTED\");\n    }\n}\n\nunsigned int connected_t1;\nvoid tox_connection_status(Tox *tox, TOX_CONNECTION connection_status, void *user_data)\n{\n    if (*((uint32_t *)user_data) != 974536)\n        return;\n\n    if (connected_t1 && !connection_status)\n        ck_abort_msg(\"Tox went offline\");\n\n    ck_assert_msg(connection_status == TOX_CONNECTION_UDP, \"wrong status %u\", connection_status);\n\n    connected_t1 = connection_status;\n}\n\nSTART_TEST(test_one)\n{\n    {\n        TOX_ERR_OPTIONS_NEW o_err;\n        struct Tox_Options *o1 = tox_options_new(&o_err);\n        struct Tox_Options o2;\n        tox_options_default(&o2);\n        ck_assert_msg(o_err == TOX_ERR_OPTIONS_NEW_OK, \"tox_options_new wrong error\");\n        ck_assert_msg(memcmp(o1, &o2, sizeof(struct Tox_Options)) == 0, \"tox_options_new error\");\n        tox_options_free(o1);\n    }\n\n    Tox *tox1 = tox_new(0, 0);\n    Tox *tox2 = tox_new(0, 0);\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(tox1, &error) == 33445, \"First Tox instance did not bind to udp port 33445.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox1, address);\n    TOX_ERR_FRIEND_ADD error;\n    uint32_t ret = tox_friend_add(tox1, address, (uint8_t *)\"m\", 1, &error);\n    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_OWN_KEY, \"Adding own address worked.\");\n\n    tox_self_get_address(tox2, address);\n    uint8_t message[TOX_MAX_FRIEND_REQUEST_LENGTH + 1];\n    ret = tox_friend_add(tox1, address, NULL, 0, &error);\n    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_NULL, \"Sending request with no message worked.\");\n    ret = tox_friend_add(tox1, address, message, 0, &error);\n    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_NO_MESSAGE, \"Sending request with no message worked.\");\n    ret = tox_friend_add(tox1, address, message, sizeof(message), &error);\n    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_TOO_LONG,\n                  \"TOX_MAX_FRIEND_REQUEST_LENGTH is too big.\");\n\n    address[0]++;\n    ret = tox_friend_add(tox1, address, (uint8_t *)\"m\", 1, &error);\n    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_BAD_CHECKSUM,\n                  \"Adding address with bad checksum worked.\");\n\n    tox_self_get_address(tox2, address);\n    ret = tox_friend_add(tox1, address, message, TOX_MAX_FRIEND_REQUEST_LENGTH, &error);\n    ck_assert_msg(ret == 0 && error == TOX_ERR_FRIEND_ADD_OK, \"Failed to add friend.\");\n    ret = tox_friend_add(tox1, address, message, TOX_MAX_FRIEND_REQUEST_LENGTH, &error);\n    ck_assert_msg(ret == UINT32_MAX && error == TOX_ERR_FRIEND_ADD_ALREADY_SENT, \"Adding friend twice worked.\");\n\n    uint8_t name[TOX_MAX_NAME_LENGTH];\n    int i;\n\n    for (i = 0; i < TOX_MAX_NAME_LENGTH; ++i) {\n        name[i] = rand();\n    }\n\n    tox_self_set_name(tox1, name, sizeof(name), 0);\n    ck_assert_msg(tox_self_get_name_size(tox1) == sizeof(name), \"Can't set name of TOX_MAX_NAME_LENGTH\");\n\n    tox_self_get_address(tox1, address);\n    size_t save_size = tox_get_savedata_size(tox1);\n    uint8_t data[save_size];\n    tox_get_savedata(tox1, data);\n\n    tox_kill(tox2);\n    TOX_ERR_NEW err_n;\n\n    struct Tox_Options options;\n    tox_options_default(&options);\n    options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;\n    options.savedata_data = data;\n    options.savedata_length = save_size;\n    tox2 = tox_new(&options, &err_n);\n    ck_assert_msg(err_n == TOX_ERR_NEW_OK, \"Load failed\");\n\n    ck_assert_msg(tox_self_get_name_size(tox2) == sizeof name, \"Wrong name size.\");\n\n    uint8_t address2[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox2, address2);\n    ck_assert_msg(memcmp(address2, address, TOX_ADDRESS_SIZE) == 0, \"Wrong address.\");\n    uint8_t new_name[TOX_MAX_NAME_LENGTH] = { 0 };\n    tox_self_get_name(tox2, new_name);\n    ck_assert_msg(memcmp(name, new_name, TOX_MAX_NAME_LENGTH) == 0, \"Wrong name\");\n\n    uint8_t sk[TOX_SECRET_KEY_SIZE];\n    tox_self_get_secret_key(tox2, sk);\n    tox_kill(tox2);\n\n    tox_options_default(&options);\n    options.savedata_type = TOX_SAVEDATA_TYPE_SECRET_KEY;\n    options.savedata_data = sk;\n    options.savedata_length = sizeof(sk);\n    tox2 = tox_new(&options, &err_n);\n    ck_assert_msg(err_n == TOX_ERR_NEW_OK, \"Load failed\");\n    uint8_t address3[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox2, address3);\n    ck_assert_msg(memcmp(address3, address, TOX_PUBLIC_KEY_SIZE) == 0, \"Wrong public key.\");\n    uint8_t pk[TOX_PUBLIC_KEY_SIZE];\n    tox_self_get_public_key(tox2, pk);\n    ck_assert_msg(memcmp(pk, address, TOX_PUBLIC_KEY_SIZE) == 0, \"Wrong public key.\");\n\n    tox_kill(tox1);\n    tox_kill(tox2);\n}\nEND_TEST\n\nSTART_TEST(test_few_clients)\n{\n    long long unsigned int con_time, cur_time = time(NULL);\n    TOX_ERR_NEW t_n_error;\n    Tox *tox1 = tox_new(0, &t_n_error);\n    ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, \"wrong error\");\n    Tox *tox2 = tox_new(0, &t_n_error);\n    ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, \"wrong error\");\n    Tox *tox3 = tox_new(0, &t_n_error);\n    ck_assert_msg(t_n_error == TOX_ERR_NEW_OK, \"wrong error\");\n\n    ck_assert_msg(tox1 || tox2 || tox3, \"Failed to create 3 tox instances\");\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(tox1, &error) == 33445, \"First Tox instance did not bind to udp port 33445.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(tox2, &error) == 33446, \"Second Tox instance did not bind to udp port 33446.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(tox3, &error) == 33447, \"Third Tox instance did not bind to udp port 33447.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    uint32_t to_compare = 974536;\n    connected_t1 = 0;\n    tox_callback_self_connection_status(tox1, tox_connection_status, &to_compare);\n    tox_callback_friend_request(tox2, accept_friend_request, &to_compare);\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox2, address);\n    uint32_t test = tox_friend_add(tox3, address, (uint8_t *)\"Gentoo\", 7, 0);\n    ck_assert_msg(test == 0, \"Failed to add friend error code: %i\", test);\n\n    uint8_t off = 1;\n\n    while (1) {\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (tox_self_get_connection_status(tox1) && tox_self_get_connection_status(tox2)\n                && tox_self_get_connection_status(tox3)) {\n            if (off) {\n                printf(\"Toxes are online, took %llu seconds\\n\", time(NULL) - cur_time);\n                con_time = time(NULL);\n                off = 0;\n            }\n\n            if (tox_friend_get_connection_status(tox2, 0, 0) == TOX_CONNECTION_UDP\n                    && tox_friend_get_connection_status(tox3, 0, 0) == TOX_CONNECTION_UDP)\n                break;\n        }\n\n        c_sleep(50);\n    }\n\n    ck_assert_msg(connected_t1, \"Tox1 isn't connected. %u\", connected_t1);\n    printf(\"tox clients connected took %llu seconds\\n\", time(NULL) - con_time);\n    to_compare = 974536;\n    tox_callback_friend_message(tox3, print_message, &to_compare);\n    uint8_t msgs[TOX_MAX_MESSAGE_LENGTH + 1];\n    memset(msgs, 'G', sizeof(msgs));\n    TOX_ERR_FRIEND_SEND_MESSAGE errm;\n    tox_friend_send_message(tox2, 0, TOX_MESSAGE_TYPE_NORMAL, msgs, TOX_MAX_MESSAGE_LENGTH + 1, &errm);\n    ck_assert_msg(errm == TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG, \"TOX_MAX_MESSAGE_LENGTH is too small\\n\");\n    tox_friend_send_message(tox2, 0, TOX_MESSAGE_TYPE_NORMAL, msgs, TOX_MAX_MESSAGE_LENGTH, &errm);\n    ck_assert_msg(errm == TOX_ERR_FRIEND_SEND_MESSAGE_OK, \"TOX_MAX_MESSAGE_LENGTH is too big\\n\");\n\n    while (1) {\n        messages_received = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (messages_received)\n            break;\n\n        c_sleep(50);\n    }\n\n    printf(\"tox clients messaging succeeded\\n\");\n\n    unsigned int save_size1 = tox_get_savedata_size(tox2);\n    ck_assert_msg(save_size1 != 0 && save_size1 < 4096, \"save is invalid size %u\", save_size1);\n    printf(\"%u\\n\", save_size1);\n    uint8_t save1[save_size1];\n    tox_get_savedata(tox2, save1);\n    tox_kill(tox2);\n\n    struct Tox_Options options;\n    tox_options_default(&options);\n    options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;\n    options.savedata_data = save1;\n    options.savedata_length = save_size1;\n    tox2 = tox_new(&options, NULL);\n    cur_time = time(NULL);\n    off = 1;\n\n    while (1) {\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (tox_self_get_connection_status(tox1) && tox_self_get_connection_status(tox2)\n                && tox_self_get_connection_status(tox3)) {\n            if (off) {\n                printf(\"Toxes are online again after reloading, took %llu seconds\\n\", time(NULL) - cur_time);\n                con_time = time(NULL);\n                off = 0;\n            }\n\n            if (tox_friend_get_connection_status(tox2, 0, 0) == TOX_CONNECTION_UDP\n                    && tox_friend_get_connection_status(tox3, 0, 0) == TOX_CONNECTION_UDP)\n                break;\n        }\n\n        c_sleep(50);\n    }\n\n    printf(\"tox clients connected took %llu seconds\\n\", time(NULL) - con_time);\n    tox_callback_friend_name(tox3, print_nickchange, &to_compare);\n    TOX_ERR_SET_INFO err_n;\n    bool succ = tox_self_set_name(tox2, (uint8_t *)\"Gentoo\", sizeof(\"Gentoo\"), &err_n);\n    ck_assert_msg(succ && err_n == TOX_ERR_SET_INFO_OK, \"tox_self_set_name failed because %u\\n\", err_n);\n\n    while (1) {\n        name_changes = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (name_changes)\n            break;\n\n        c_sleep(50);\n    }\n\n    ck_assert_msg(tox_friend_get_name_size(tox3, 0, 0) == sizeof(\"Gentoo\"), \"Name length not correct\");\n    uint8_t temp_name[sizeof(\"Gentoo\")];\n    tox_friend_get_name(tox3, 0, temp_name, 0);\n    ck_assert_msg(memcmp(temp_name, \"Gentoo\", sizeof(\"Gentoo\")) == 0, \"Name not correct\");\n\n    tox_callback_friend_status_message(tox3, print_status_m_change, &to_compare);\n    succ = tox_self_set_status_message(tox2, (uint8_t *)\"Installing Gentoo\", sizeof(\"Installing Gentoo\"), &err_n);\n    ck_assert_msg(succ && err_n == TOX_ERR_SET_INFO_OK, \"tox_self_set_status_message failed because %u\\n\", err_n);\n\n    while (1) {\n        status_m_changes = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (status_m_changes)\n            break;\n\n        c_sleep(50);\n    }\n\n    ck_assert_msg(tox_friend_get_status_message_size(tox3, 0, 0) == sizeof(\"Installing Gentoo\"),\n                  \"status message length not correct\");\n    uint8_t temp_status_m[sizeof(\"Installing Gentoo\")];\n    tox_friend_get_status_message(tox3, 0, temp_status_m, 0);\n    ck_assert_msg(memcmp(temp_status_m, \"Installing Gentoo\", sizeof(\"Installing Gentoo\")) == 0,\n                  \"status message not correct\");\n\n    tox_callback_friend_typing(tox2, &print_typingchange, &to_compare);\n    tox_self_set_typing(tox3, 0, 1, 0);\n\n    while (1) {\n        typing_changes = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n\n        if (typing_changes == 2)\n            break;\n        else\n            ck_assert_msg(typing_changes == 0, \"Typing fail\");\n\n        c_sleep(50);\n    }\n\n    ck_assert_msg(tox_friend_get_typing(tox2, 0, 0) == 1, \"Typing fail\");\n    tox_self_set_typing(tox3, 0, 0, 0);\n\n    while (1) {\n        typing_changes = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (typing_changes == 1)\n            break;\n        else\n            ck_assert_msg(typing_changes == 0, \"Typing fail\");\n\n        c_sleep(50);\n    }\n\n    TOX_ERR_FRIEND_QUERY err_t;\n    ck_assert_msg(tox_friend_get_typing(tox2, 0, &err_t) == 0, \"Typing fail\");\n    ck_assert_msg(err_t == TOX_ERR_FRIEND_QUERY_OK, \"Typing fail\");\n\n    uint32_t packet_number = 160;\n    tox_callback_friend_lossless_packet(tox3, &handle_custom_packet, &packet_number);\n    uint8_t data_c[TOX_MAX_CUSTOM_PACKET_SIZE + 1];\n    memset(data_c, ((uint8_t)packet_number), sizeof(data_c));\n    int ret = tox_friend_send_lossless_packet(tox2, 0, data_c, sizeof(data_c), 0);\n    ck_assert_msg(ret == 0, \"tox_friend_send_lossless_packet bigger fail %i\", ret);\n    ret = tox_friend_send_lossless_packet(tox2, 0, data_c, TOX_MAX_CUSTOM_PACKET_SIZE, 0);\n    ck_assert_msg(ret == 1, \"tox_friend_send_lossless_packet fail %i\", ret);\n\n    while (1) {\n        custom_packet = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (custom_packet == 1)\n            break;\n        else\n            ck_assert_msg(custom_packet == 0, \"Lossless packet fail\");\n\n        c_sleep(50);\n    }\n\n    packet_number = 200;\n    tox_callback_friend_lossy_packet(tox3, &handle_custom_packet, &packet_number);\n    memset(data_c, ((uint8_t)packet_number), sizeof(data_c));\n    ret = tox_friend_send_lossy_packet(tox2, 0, data_c, sizeof(data_c), 0);\n    ck_assert_msg(ret == 0, \"tox_friend_send_lossy_packet bigger fail %i\", ret);\n    ret = tox_friend_send_lossy_packet(tox2, 0, data_c, TOX_MAX_CUSTOM_PACKET_SIZE, 0);\n    ck_assert_msg(ret == 1, \"tox_friend_send_lossy_packet fail %i\", ret);\n\n    while (1) {\n        custom_packet = 0;\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (custom_packet == 1)\n            break;\n        else\n            ck_assert_msg(custom_packet == 0, \"lossy packet fail\");\n\n        c_sleep(50);\n    }\n\n    printf(\"Starting file transfer test.\\n\");\n\n    file_accepted = file_size = file_recv = sendf_ok = size_recv = 0;\n    max_sending = UINT64_MAX;\n    long long unsigned int f_time = time(NULL);\n    tox_callback_file_recv_chunk(tox3, write_file, &to_compare);\n    tox_callback_file_recv_control(tox2, file_print_control, &to_compare);\n    tox_callback_file_chunk_request(tox2, tox_file_chunk_request, &to_compare);\n    tox_callback_file_recv_control(tox3, file_print_control, &to_compare);\n    tox_callback_file_recv(tox3, tox_file_receive, &to_compare);\n    uint64_t totalf_size = 100 * 1024 * 1024;\n    uint32_t fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, 0, (uint8_t *)\"Gentoo.exe\",\n                                  sizeof(\"Gentoo.exe\"), 0);\n    ck_assert_msg(fnum != UINT32_MAX, \"tox_new_file_sender fail\");\n\n    TOX_ERR_FILE_GET gfierr;\n    ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), \"tox_file_get_file_id didn't fail\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, \"wrong error\");\n    ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), \"tox_file_get_file_id didn't fail\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, \"wrong error\");\n    ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), \"tox_file_get_file_id failed\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, \"wrong error\");\n\n    while (1) {\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (file_sending_done) {\n            if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv\n                    && file_accepted == 1) {\n                break;\n            } else {\n                ck_abort_msg(\"Something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu\", sendf_ok, file_recv,\n                             totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, totalf_size, size_recv,\n                             sending_pos);\n            }\n        }\n\n        uint32_t tox1_interval = tox_iteration_interval(tox1);\n        uint32_t tox2_interval = tox_iteration_interval(tox2);\n        uint32_t tox3_interval = tox_iteration_interval(tox3);\n\n        if (tox2_interval > tox3_interval) {\n            c_sleep(tox3_interval);\n        } else {\n            c_sleep(tox2_interval);\n        }\n    }\n\n    printf(\"100MB file sent in %llu seconds\\n\", time(NULL) - f_time);\n\n    printf(\"Starting file streaming transfer test.\\n\");\n\n    file_sending_done = file_accepted = file_size = file_recv = sendf_ok = size_recv = 0;\n    f_time = time(NULL);\n    tox_callback_file_recv_chunk(tox3, write_file, &to_compare);\n    tox_callback_file_recv_control(tox2, file_print_control, &to_compare);\n    tox_callback_file_chunk_request(tox2, tox_file_chunk_request, &to_compare);\n    tox_callback_file_recv_control(tox3, file_print_control, &to_compare);\n    tox_callback_file_recv(tox3, tox_file_receive, &to_compare);\n    totalf_size = UINT64_MAX;\n    fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, 0, (uint8_t *)\"Gentoo.exe\", sizeof(\"Gentoo.exe\"), 0);\n    ck_assert_msg(fnum != UINT32_MAX, \"tox_new_file_sender fail\");\n\n    ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), \"tox_file_get_file_id didn't fail\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, \"wrong error\");\n    ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), \"tox_file_get_file_id didn't fail\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, \"wrong error\");\n    ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), \"tox_file_get_file_id failed\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, \"wrong error\");\n\n    max_sending = 100 * 1024;\n    m_send_reached = 0;\n\n    while (1) {\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (file_sending_done) {\n            if (sendf_ok && file_recv && m_send_reached && totalf_size == file_size && size_recv == max_sending\n                    && sending_pos == size_recv && file_accepted == 1) {\n                break;\n            } else {\n                ck_abort_msg(\"Something went wrong in file transfer %u %u %u %u %u %u %u %llu %llu %llu %llu\", sendf_ok, file_recv,\n                             m_send_reached, totalf_size == file_size, size_recv == max_sending, sending_pos == size_recv, file_accepted == 1,\n                             totalf_size, file_size,\n                             size_recv, sending_pos);\n            }\n        }\n\n        uint32_t tox1_interval = tox_iteration_interval(tox1);\n        uint32_t tox2_interval = tox_iteration_interval(tox2);\n        uint32_t tox3_interval = tox_iteration_interval(tox3);\n\n        if (tox2_interval > tox3_interval) {\n            c_sleep(tox3_interval);\n        } else {\n            c_sleep(tox2_interval);\n        }\n    }\n\n    printf(\"Starting file 0 transfer test.\\n\");\n\n    file_sending_done = file_accepted = file_size = file_recv = sendf_ok = size_recv = 0;\n    f_time = time(NULL);\n    tox_callback_file_recv_chunk(tox3, write_file, &to_compare);\n    tox_callback_file_recv_control(tox2, file_print_control, &to_compare);\n    tox_callback_file_chunk_request(tox2, tox_file_chunk_request, &to_compare);\n    tox_callback_file_recv_control(tox3, file_print_control, &to_compare);\n    tox_callback_file_recv(tox3, tox_file_receive, &to_compare);\n    totalf_size = 0;\n    fnum = tox_file_send(tox2, 0, TOX_FILE_KIND_DATA, totalf_size, 0, (uint8_t *)\"Gentoo.exe\", sizeof(\"Gentoo.exe\"), 0);\n    ck_assert_msg(fnum != UINT32_MAX, \"tox_new_file_sender fail\");\n\n    ck_assert_msg(!tox_file_get_file_id(tox2, 1, fnum, file_cmp_id, &gfierr), \"tox_file_get_file_id didn't fail\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, \"wrong error\");\n    ck_assert_msg(!tox_file_get_file_id(tox2, 0, fnum + 1, file_cmp_id, &gfierr), \"tox_file_get_file_id didn't fail\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_NOT_FOUND, \"wrong error\");\n    ck_assert_msg(tox_file_get_file_id(tox2, 0, fnum, file_cmp_id, &gfierr), \"tox_file_get_file_id failed\");\n    ck_assert_msg(gfierr == TOX_ERR_FILE_GET_OK, \"wrong error\");\n\n\n    while (1) {\n        tox_iterate(tox1);\n        tox_iterate(tox2);\n        tox_iterate(tox3);\n\n        if (file_sending_done) {\n            if (sendf_ok && file_recv && totalf_size == file_size && size_recv == file_size && sending_pos == size_recv\n                    && file_accepted == 1) {\n                break;\n            } else {\n                ck_abort_msg(\"Something went wrong in file transfer %u %u %u %u %u %u %llu %llu %llu\", sendf_ok, file_recv,\n                             totalf_size == file_size, size_recv == file_size, sending_pos == size_recv, file_accepted == 1, totalf_size, size_recv,\n                             sending_pos);\n            }\n        }\n\n        uint32_t tox1_interval = tox_iteration_interval(tox1);\n        uint32_t tox2_interval = tox_iteration_interval(tox2);\n        uint32_t tox3_interval = tox_iteration_interval(tox3);\n\n        if (tox2_interval > tox3_interval) {\n            c_sleep(tox3_interval);\n        } else {\n            c_sleep(tox2_interval);\n        }\n    }\n\n    printf(\"test_few_clients succeeded, took %llu seconds\\n\", time(NULL) - cur_time);\n\n    tox_kill(tox1);\n    tox_kill(tox2);\n    tox_kill(tox3);\n}\nEND_TEST\n\n#define NUM_TOXES 90\n#define NUM_FRIENDS 50\n\nSTART_TEST(test_many_clients)\n{\n    long long unsigned int cur_time = time(NULL);\n    Tox *toxes[NUM_TOXES];\n    uint32_t i, j;\n    uint32_t to_comp = 974536;\n\n    for (i = 0; i < NUM_TOXES; ++i) {\n        toxes[i] = tox_new(0, 0);\n        ck_assert_msg(toxes[i] != 0, \"Failed to create tox instances %u\", i);\n        tox_callback_friend_request(toxes[i], accept_friend_request, &to_comp);\n    }\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(toxes[0], &error) == 33445, \"First Tox instance did not bind to udp port 33445.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    struct {\n        uint16_t tox1;\n        uint16_t tox2;\n    } pairs[NUM_FRIENDS];\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    unsigned int num_f = 0;\n\n    for (i = 0; i < NUM_TOXES; ++i) {\n        num_f += tox_self_get_friend_list_size(toxes[i]);\n    }\n\n    ck_assert_msg(num_f == 0, \"bad num friends: %u\", num_f);\n\n    for (i = 0; i < NUM_FRIENDS; ++i) {\nloop_top:\n        pairs[i].tox1 = rand() % NUM_TOXES;\n        pairs[i].tox2 = (pairs[i].tox1 + rand() % (NUM_TOXES - 1) + 1) % NUM_TOXES;\n\n        for (j = 0; j < i; ++j) {\n            if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2)\n                goto loop_top;\n        }\n\n        tox_self_get_address(toxes[pairs[i].tox1], address);\n\n        TOX_ERR_FRIEND_ADD test;\n        uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (uint8_t *)\"Gentoo\", 7, &test);\n\n        if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) {\n            goto loop_top;\n        }\n\n        ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, \"Failed to add friend error code: %i\", test);\n    }\n\n    for (i = 0; i < NUM_TOXES; ++i) {\n        num_f += tox_self_get_friend_list_size(toxes[i]);\n    }\n\n    ck_assert_msg(num_f == NUM_FRIENDS, \"bad num friends: %u\", num_f);\n\n    while (1) {\n        uint16_t counter = 0;\n\n        for (i = 0; i < NUM_TOXES; ++i) {\n            for (j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j)\n                if (tox_friend_get_connection_status(toxes[i], j, 0) == TOX_CONNECTION_UDP)\n                    ++counter;\n        }\n\n        if (counter == NUM_FRIENDS * 2) {\n            break;\n        }\n\n        for (i = 0; i < NUM_TOXES; ++i) {\n            tox_iterate(toxes[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    for (i = 0; i < NUM_TOXES; ++i) {\n        tox_kill(toxes[i]);\n    }\n\n    printf(\"test_many_clients succeeded, took %llu seconds\\n\", time(NULL) - cur_time);\n}\nEND_TEST\n\n#define NUM_TOXES_TCP 40\n#define TCP_RELAY_PORT 33448\n\nSTART_TEST(test_many_clients_tcp)\n{\n    long long unsigned int cur_time = time(NULL);\n    Tox *toxes[NUM_TOXES_TCP];\n    uint32_t i, j;\n    uint32_t to_comp = 974536;\n\n    for (i = 0; i < NUM_TOXES_TCP; ++i) {\n        struct Tox_Options opts;\n        tox_options_default(&opts);\n\n        if (i == 0) {\n            opts.tcp_port = TCP_RELAY_PORT;\n        } else {\n            opts.udp_enabled = 0;\n        }\n\n        toxes[i] = tox_new(&opts, 0);\n        ck_assert_msg(toxes[i] != 0, \"Failed to create tox instances %u\", i);\n        tox_callback_friend_request(toxes[i], accept_friend_request, &to_comp);\n        uint8_t dpk[TOX_PUBLIC_KEY_SIZE];\n        tox_self_get_dht_id(toxes[0], dpk);\n        ck_assert_msg(tox_add_tcp_relay(toxes[i], \"::1\", TCP_RELAY_PORT, dpk, 0), \"add relay error\");\n        ck_assert_msg(tox_bootstrap(toxes[i], \"::1\", 33445, dpk, 0), \"Bootstrap error\");\n    }\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(toxes[0], &error) == 33445, \"First Tox instance did not bind to udp port 33445.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n        ck_assert_msg(tox_self_get_tcp_port(toxes[0], &error) == TCP_RELAY_PORT,\n                      \"First Tox instance did not bind to tcp port %u.\\n\", TCP_RELAY_PORT);\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    struct {\n        uint16_t tox1;\n        uint16_t tox2;\n    } pairs[NUM_FRIENDS];\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    for (i = 0; i < NUM_FRIENDS; ++i) {\nloop_top:\n        pairs[i].tox1 = rand() % NUM_TOXES_TCP;\n        pairs[i].tox2 = (pairs[i].tox1 + rand() % (NUM_TOXES_TCP - 1) + 1) % NUM_TOXES_TCP;\n\n        for (j = 0; j < i; ++j) {\n            if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2)\n                goto loop_top;\n        }\n\n        tox_self_get_address(toxes[pairs[i].tox1], address);\n\n        TOX_ERR_FRIEND_ADD test;\n        uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (uint8_t *)\"Gentoo\", 7, &test);\n\n        if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) {\n            goto loop_top;\n        }\n\n        ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, \"Failed to add friend error code: %i\", test);\n    }\n\n    while (1) {\n        uint16_t counter = 0, cc = 0;\n\n        for (i = 0; i < NUM_TOXES_TCP; ++i) {\n            for (j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j)\n                if (tox_friend_get_connection_status(toxes[i], j, 0) == TOX_CONNECTION_TCP)\n                    ++counter;\n\n        }\n\n        if (counter == NUM_FRIENDS * 2) {\n            break;\n        }\n\n        for (i = 0; i < NUM_TOXES_TCP; ++i) {\n            tox_iterate(toxes[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    for (i = 0; i < NUM_TOXES_TCP; ++i) {\n        tox_kill(toxes[i]);\n    }\n\n    printf(\"test_many_clients_tcp succeeded, took %llu seconds\\n\", time(NULL) - cur_time);\n}\nEND_TEST\n\n#define NUM_TCP_RELAYS 3\n\nSTART_TEST(test_many_clients_tcp_b)\n{\n    long long unsigned int cur_time = time(NULL);\n    Tox *toxes[NUM_TOXES_TCP];\n    uint32_t i, j;\n    uint32_t to_comp = 974536;\n\n    for (i = 0; i < NUM_TOXES_TCP; ++i) {\n        struct Tox_Options opts;\n        tox_options_default(&opts);\n\n        if (i < NUM_TCP_RELAYS) {\n            opts.tcp_port = TCP_RELAY_PORT + i;\n        } else {\n            opts.udp_enabled = 0;\n        }\n\n        toxes[i] = tox_new(&opts, 0);\n        ck_assert_msg(toxes[i] != 0, \"Failed to create tox instances %u\", i);\n        tox_callback_friend_request(toxes[i], accept_friend_request, &to_comp);\n        uint8_t dpk[TOX_PUBLIC_KEY_SIZE];\n        tox_self_get_dht_id(toxes[(i % NUM_TCP_RELAYS)], dpk);\n        ck_assert_msg(tox_add_tcp_relay(toxes[i], \"::1\", TCP_RELAY_PORT + (i % NUM_TCP_RELAYS), dpk, 0), \"add relay error\");\n        tox_self_get_dht_id(toxes[0], dpk);\n        ck_assert_msg(tox_bootstrap(toxes[i], \"::1\", 33445, dpk, 0), \"Bootstrap error\");\n    }\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(toxes[0], &error) == 33445, \"First Tox instance did not bind to udp port 33445.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n        ck_assert_msg(tox_self_get_tcp_port(toxes[0], &error) == TCP_RELAY_PORT,\n                      \"First Tox instance did not bind to tcp port %u.\\n\", TCP_RELAY_PORT);\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    struct {\n        uint16_t tox1;\n        uint16_t tox2;\n    } pairs[NUM_FRIENDS];\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    for (i = 0; i < NUM_FRIENDS; ++i) {\nloop_top:\n        pairs[i].tox1 = rand() % NUM_TOXES_TCP;\n        pairs[i].tox2 = (pairs[i].tox1 + rand() % (NUM_TOXES_TCP - 1) + 1) % NUM_TOXES_TCP;\n\n        for (j = 0; j < i; ++j) {\n            if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2)\n                goto loop_top;\n        }\n\n        tox_self_get_address(toxes[pairs[i].tox1], address);\n\n        TOX_ERR_FRIEND_ADD test;\n        uint32_t num = tox_friend_add(toxes[pairs[i].tox2], address, (uint8_t *)\"Gentoo\", 7, &test);\n\n        if (test == TOX_ERR_FRIEND_ADD_ALREADY_SENT) {\n            goto loop_top;\n        }\n\n        ck_assert_msg(num != UINT32_MAX && test == TOX_ERR_FRIEND_ADD_OK, \"Failed to add friend error code: %i\", test);\n    }\n\n    while (1) {\n        uint16_t counter = 0;\n\n        for (i = 0; i < NUM_TOXES_TCP; ++i) {\n            for (j = 0; j < tox_self_get_friend_list_size(toxes[i]); ++j)\n                if (tox_friend_get_connection_status(toxes[i], j, 0) == TOX_CONNECTION_TCP)\n                    ++counter;\n        }\n\n        if (counter == NUM_FRIENDS * 2) {\n            break;\n        }\n\n        for (i = 0; i < NUM_TOXES_TCP; ++i) {\n            tox_iterate(toxes[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    for (i = 0; i < NUM_TOXES_TCP; ++i) {\n        tox_kill(toxes[i]);\n    }\n\n    printf(\"test_many_clients_tcp_b succeeded, took %llu seconds\\n\", time(NULL) - cur_time);\n}\nEND_TEST\n\n\n#define NUM_GROUP_TOX 32\n\nvoid g_accept_friend_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    if (*((uint32_t *)userdata) != 234212)\n        return;\n\n    if (length == 7 && memcmp(\"Gentoo\", data, 7) == 0) {\n        tox_friend_add_norequest(m, public_key, 0);\n    }\n}\n\nstatic Tox *invite_tox;\nstatic unsigned int invite_counter;\n\nvoid print_group_invite_callback(Tox *tox, int32_t friendnumber, uint8_t type, const uint8_t *data, uint16_t length,\n                                 void *userdata)\n{\n    if (*((uint32_t *)userdata) != 234212)\n        return;\n\n    if (type != TOX_GROUPCHAT_TYPE_TEXT)\n        return;\n\n    int g_num;\n\n    if ((g_num = tox_join_groupchat(tox, friendnumber, data, length)) == -1)\n        return;\n\n    ck_assert_msg(g_num == 0, \"Group number was not 0\");\n    ck_assert_msg(tox_join_groupchat(tox, friendnumber, data, length) == -1,\n                  \"Joining groupchat twice should be impossible.\");\n\n    invite_tox = tox;\n    invite_counter = 4;\n}\n\nstatic unsigned int num_recv;\n\nvoid print_group_message(Tox *tox, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,\n                         void *userdata)\n{\n    if (*((uint32_t *)userdata) != 234212)\n        return;\n\n    if (length == (sizeof(\"Install Gentoo\") - 1) && memcmp(message, \"Install Gentoo\", sizeof(\"Install Gentoo\") - 1) == 0) {\n        ++num_recv;\n    }\n}\n\nSTART_TEST(test_many_group)\n{\n    long long unsigned int cur_time = time(NULL);\n    Tox *toxes[NUM_GROUP_TOX];\n    unsigned int i, j, k;\n\n    uint32_t to_comp = 234212;\n\n    for (i = 0; i < NUM_GROUP_TOX; ++i) {\n        toxes[i] = tox_new(0, 0);\n        ck_assert_msg(toxes[i] != 0, \"Failed to create tox instances %u\", i);\n        tox_callback_friend_request(toxes[i], &g_accept_friend_request, &to_comp);\n        tox_callback_group_invite(toxes[i], &print_group_invite_callback, &to_comp);\n    }\n\n    {\n        TOX_ERR_GET_PORT error;\n        ck_assert_msg(tox_self_get_udp_port(toxes[0], &error) == 33445, \"First Tox instance did not bind to udp port 33445.\\n\");\n        ck_assert_msg(error == TOX_ERR_GET_PORT_OK, \"wrong error\");\n    }\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(toxes[NUM_GROUP_TOX - 1], address);\n\n    for (i = 0; i < NUM_GROUP_TOX; ++i) {\n        ck_assert_msg(tox_friend_add(toxes[i], address, (uint8_t *)\"Gentoo\", 7, 0) == 0, \"Failed to add friend\");\n\n        tox_self_get_address(toxes[i], address);\n    }\n\n    while (1) {\n        for (i = 0; i < NUM_GROUP_TOX; ++i) {\n            if (tox_friend_get_connection_status(toxes[i], 0, 0) != TOX_CONNECTION_UDP) {\n                break;\n            }\n        }\n\n        if (i == NUM_GROUP_TOX)\n            break;\n\n        for (i = 0; i < NUM_GROUP_TOX; ++i) {\n            tox_iterate(toxes[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    printf(\"friends connected, took %llu seconds\\n\", time(NULL) - cur_time);\n\n    ck_assert_msg(tox_add_groupchat(toxes[0]) != -1, \"Failed to create group\");\n    ck_assert_msg(tox_invite_friend(toxes[0], 0, 0) == 0, \"Failed to invite friend\");\n    ck_assert_msg(tox_group_set_title(toxes[0], 0, \"Gentoo\", sizeof(\"Gentoo\") - 1) == 0, \"Failed to set group title\");\n    invite_counter = ~0;\n\n    unsigned int done = ~0;\n    done -= 5;\n\n    while (1) {\n        for (i = 0; i < NUM_GROUP_TOX; ++i) {\n            tox_iterate(toxes[i]);\n        }\n\n        if (!invite_counter) {\n            ck_assert_msg(tox_invite_friend(invite_tox, 0, 0) == 0, \"Failed to invite friend\");\n        }\n\n        if (done == invite_counter) {\n            break;\n        }\n\n        --invite_counter;\n        c_sleep(50);\n    }\n\n    for (i = 0; i < NUM_GROUP_TOX; ++i) {\n        int num_peers = tox_group_number_peers(toxes[i], 0);\n        ck_assert_msg(num_peers == NUM_GROUP_TOX, \"Bad number of group peers. expected: %u got: %i, tox %u\", NUM_GROUP_TOX,\n                      num_peers, i);\n\n        uint8_t title[2048];\n        int ret = tox_group_get_title(toxes[i], 0, title, sizeof(title));\n        ck_assert_msg(ret == sizeof(\"Gentoo\") - 1, \"Wrong title length\");\n        ck_assert_msg(memcmp(\"Gentoo\", title, ret) == 0, \"Wrong title\");\n    }\n\n    printf(\"group connected\\n\");\n\n    for (i = 0; i < NUM_GROUP_TOX; ++i) {\n        tox_callback_group_message(toxes[i], &print_group_message, &to_comp);\n    }\n\n    ck_assert_msg(tox_group_message_send(toxes[rand() % NUM_GROUP_TOX], 0, (uint8_t *)\"Install Gentoo\",\n                                         sizeof(\"Install Gentoo\") - 1) == 0, \"Failed to send group message.\");\n    num_recv = 0;\n\n    for (j = 0; j < 20; ++j) {\n        for (i = 0; i < NUM_GROUP_TOX; ++i) {\n            tox_iterate(toxes[i]);\n        }\n\n        c_sleep(50);\n    }\n\n    ck_assert_msg(num_recv == NUM_GROUP_TOX, \"Failed to recv group messages.\");\n\n    for (k = NUM_GROUP_TOX; k != 0 ; --k) {\n        tox_del_groupchat(toxes[k - 1], 0);\n\n        for (j = 0; j < 10; ++j) {\n            for (i = 0; i < NUM_GROUP_TOX; ++i) {\n                tox_iterate(toxes[i]);\n            }\n\n            c_sleep(50);\n        }\n\n        for (i = 0; i < (k - 1); ++i) {\n            int num_peers = tox_group_number_peers(toxes[i], 0);\n            ck_assert_msg(num_peers == (k - 1), \"Bad number of group peers. expected: %u got: %i, tox %u\", (k - 1), num_peers, i);\n        }\n    }\n\n    for (i = 0; i < NUM_GROUP_TOX; ++i) {\n        tox_kill(toxes[i]);\n    }\n\n    printf(\"test_many_group succeeded, took %llu seconds\\n\", time(NULL) - cur_time);\n}\nEND_TEST\n\nSuite *tox_suite(void)\n{\n    Suite *s = suite_create(\"Tox\");\n\n    DEFTESTCASE(one);\n    DEFTESTCASE_SLOW(few_clients, 80);\n    DEFTESTCASE_SLOW(many_clients, 80);\n    DEFTESTCASE_SLOW(many_clients_tcp, 20);\n    DEFTESTCASE_SLOW(many_clients_tcp_b, 20);\n    DEFTESTCASE_SLOW(many_group, 100);\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    srand((unsigned int) time(NULL));\n\n    Suite *tox = tox_suite();\n    SRunner *test_runner = srunner_create(tox);\n\n    int number_failed = 0;\n    srunner_run_all(test_runner, CK_NORMAL);\n    number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n\n"
  },
  {
    "path": "auto_tests/toxav_basic_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#ifndef HAVE_LIBCHECK\n#   include <assert.h>\n\n#   define ck_assert(X) assert(X);\n#   define START_TEST(NAME) void NAME ()\n#   define END_TEST\n#else\n#   include \"helpers.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include <vpx/vpx_image.h>\n\n#include \"../toxcore/tox.h\"\n#include \"../toxcore/util.h\"\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/crypto_core.h\"\n#include \"../toxav/toxav.h\"\n\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n\n#define TEST_REGULAR_AV 1\n#define TEST_REGULAR_A 1\n#define TEST_REGULAR_V 1\n#define TEST_REJECT 1\n#define TEST_CANCEL 1\n#define TEST_MUTE_UNMUTE 1\n#define TEST_STOP_RESUME_PAYLOAD 1\n#define TEST_PAUSE_RESUME_SEND 1\n\n\ntypedef struct {\n    bool incoming;\n    uint32_t state;\n\n} CallControl;\n\n\n/**\n * Callbacks\n */\nvoid t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)\n{\n    (void) av;\n    (void) friend_number;\n    (void) audio_enabled;\n    (void) video_enabled;\n\n    printf(\"Handling CALL callback\\n\");\n    ((CallControl *)user_data)->incoming = true;\n}\nvoid t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)\n{\n    (void) av;\n    (void) friend_number;\n\n    printf(\"Handling CALL STATE callback: %d\\n\", state);\n    ((CallControl *)user_data)->state = state;\n}\nvoid t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,\n                                    uint16_t width, uint16_t height,\n                                    uint8_t const *y, uint8_t const *u, uint8_t const *v,\n                                    int32_t ystride, int32_t ustride, int32_t vstride,\n                                    void *user_data)\n{\n    (void) av;\n    (void) friend_number;\n    (void) width;\n    (void) height;\n    (void) y;\n    (void) u;\n    (void) v;\n    (void) ystride;\n    (void) ustride;\n    (void) vstride;\n    (void) user_data;\n    printf(\"Received video payload\\n\");\n}\nvoid t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,\n                                    int16_t const *pcm,\n                                    size_t sample_count,\n                                    uint8_t channels,\n                                    uint32_t sampling_rate,\n                                    void *user_data)\n{\n    (void) av;\n    (void) friend_number;\n    (void) pcm;\n    (void) sample_count;\n    (void) channels;\n    (void) sampling_rate;\n    (void) user_data;\n    printf(\"Received audio payload\\n\");\n}\nvoid t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    (void) userdata;\n\n    if (length == 7 && memcmp(\"gentoo\", data, 7) == 0) {\n        ck_assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);\n    }\n}\n\n\n/**\n * Iterate helper\n */\nint iterate_tox(Tox *bootstrap, Tox *Alice, Tox *Bob)\n{\n    tox_iterate(bootstrap);\n    tox_iterate(Alice);\n    tox_iterate(Bob);\n\n    return MIN(tox_iteration_interval(Alice), tox_iteration_interval(Bob));\n}\n\n\n\nSTART_TEST(test_AV_flows)\n{\n    Tox *Alice, *Bob, *bootstrap;\n    ToxAV *AliceAV, *BobAV;\n\n    CallControl AliceCC, BobCC;\n\n    {\n        TOX_ERR_NEW error;\n\n        bootstrap = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n\n        Alice = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n\n        Bob = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n    }\n\n    printf(\"Created 3 instances of Tox\\n\");\n    printf(\"Preparing network...\\n\");\n    long long unsigned int cur_time = time(NULL);\n\n    uint32_t to_compare = 974536;\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);\n    tox_self_get_address(Alice, address);\n\n\n    ck_assert(tox_friend_add(Bob, address, (uint8_t *)\"gentoo\", 7, NULL) != (uint32_t) ~0);\n\n    uint8_t off = 1;\n\n    while (1) {\n        iterate_tox(bootstrap, Alice, Bob);\n\n        if (tox_self_get_connection_status(bootstrap) &&\n                tox_self_get_connection_status(Alice) &&\n                tox_self_get_connection_status(Bob) && off) {\n            printf(\"Toxes are online, took %llu seconds\\n\", time(NULL) - cur_time);\n            off = 0;\n        }\n\n        if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Bob, 0, NULL) == TOX_CONNECTION_UDP)\n            break;\n\n        c_sleep(20);\n    }\n\n\n    {\n        TOXAV_ERR_NEW error;\n        AliceAV = toxav_new(Alice, &error);\n        ck_assert(error == TOXAV_ERR_NEW_OK);\n\n        BobAV = toxav_new(Bob, &error);\n        ck_assert(error == TOXAV_ERR_NEW_OK);\n    }\n\n    toxav_callback_call(AliceAV, t_toxav_call_cb, &AliceCC);\n    toxav_callback_call_state(AliceAV, t_toxav_call_state_cb, &AliceCC);\n    toxav_callback_video_receive_frame(AliceAV, t_toxav_receive_video_frame_cb, &AliceCC);\n    toxav_callback_audio_receive_frame(AliceAV, t_toxav_receive_audio_frame_cb, &AliceCC);\n\n    toxav_callback_call(BobAV, t_toxav_call_cb, &BobCC);\n    toxav_callback_call_state(BobAV, t_toxav_call_state_cb, &BobCC);\n    toxav_callback_video_receive_frame(BobAV, t_toxav_receive_video_frame_cb, &BobCC);\n    toxav_callback_audio_receive_frame(BobAV, t_toxav_receive_audio_frame_cb, &BobCC);\n\n    printf(\"Created 2 instances of ToxAV\\n\");\n    printf(\"All set after %llu seconds!\\n\", time(NULL) - cur_time);\n\n\n#define REGULAR_CALL_FLOW(A_BR, V_BR) \\\n    do { \\\n        memset(&AliceCC, 0, sizeof(CallControl)); \\\n        memset(&BobCC, 0, sizeof(CallControl)); \\\n        \\\n        TOXAV_ERR_CALL rc; \\\n        toxav_call(AliceAV, 0, A_BR, V_BR, &rc); \\\n        \\\n        if (rc != TOXAV_ERR_CALL_OK) { \\\n            printf(\"toxav_call failed: %d\\n\", rc); \\\n            ck_assert(0); \\\n        } \\\n        \\\n        \\\n        long long unsigned int start_time = time(NULL); \\\n        \\\n        \\\n        while (BobCC.state != TOXAV_FRIEND_CALL_STATE_FINISHED) { \\\n            \\\n            if (BobCC.incoming) { \\\n                TOXAV_ERR_ANSWER rc; \\\n                toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \\\n                \\\n                if (rc != TOXAV_ERR_ANSWER_OK) { \\\n                    printf(\"toxav_answer failed: %d\\n\", rc); \\\n                    ck_assert(0); \\\n                } \\\n                BobCC.incoming = false; \\\n            } else { \\\n                /* TODO rtp */ \\\n                \\\n                if (time(NULL) - start_time >= 1) { \\\n                    \\\n                    TOXAV_ERR_CALL_CONTROL rc; \\\n                    toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \\\n                    \\\n                    if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \\\n                        printf(\"toxav_call_control failed: %d\\n\", rc); \\\n                        ck_assert(0); \\\n                    } \\\n                } \\\n            } \\\n             \\\n            iterate_tox(bootstrap, Alice, Bob); \\\n        } \\\n        printf(\"Success!\\n\");\\\n    } while(0)\n\n    if (TEST_REGULAR_AV) {\n        printf(\"\\nTrying regular call (Audio and Video)...\\n\");\n        REGULAR_CALL_FLOW(48, 4000);\n    }\n\n    if (TEST_REGULAR_A) {\n        printf(\"\\nTrying regular call (Audio only)...\\n\");\n        REGULAR_CALL_FLOW(48, 0);\n    }\n\n    if (TEST_REGULAR_V) {\n        printf(\"\\nTrying regular call (Video only)...\\n\");\n        REGULAR_CALL_FLOW(0, 4000);\n    }\n\n#undef REGULAR_CALL_FLOW\n\n    if (TEST_REJECT) { /* Alice calls; Bob rejects */\n        printf(\"\\nTrying reject flow...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        {\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        /* Reject */\n        {\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(BobAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        while (AliceCC.state != TOXAV_FRIEND_CALL_STATE_FINISHED)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        printf(\"Success!\\n\");\n    }\n\n    if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */\n        printf(\"\\nTrying cancel (while ringing) flow...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        {\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        /* Cancel */\n        {\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        /* Alice will not receive end state */\n        while (BobCC.state != TOXAV_FRIEND_CALL_STATE_FINISHED)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        printf(\"Success!\\n\");\n    }\n\n    if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */\n        printf(\"\\nTrying mute functionality...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        /* Assume sending audio and video */\n        {\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 48, 1000, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        /* At first try all stuff while in invalid state */\n        ck_assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));\n        ck_assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));\n        ck_assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));\n        ck_assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));\n        ck_assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_HIDE_VIDEO, NULL));\n        ck_assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_SHOW_VIDEO, NULL));\n\n        {\n            TOXAV_ERR_ANSWER rc;\n            toxav_answer(BobAV, 0, 48, 4000, &rc);\n\n            if (rc != TOXAV_ERR_ANSWER_OK) {\n                printf(\"toxav_answer failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        iterate_tox(bootstrap, Alice, Bob);\n\n        /* Pause and Resume */\n        printf(\"Pause and Resume\\n\");\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state == 0);\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state & (TOXAV_FRIEND_CALL_STATE_SENDING_A | TOXAV_FRIEND_CALL_STATE_SENDING_V));\n\n        /* Mute/Unmute single */\n        printf(\"Mute/Unmute single\\n\");\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);\n\n        /* Mute/Unmute both */\n        printf(\"Mute/Unmute both\\n\");\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_HIDE_VIDEO, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state ^ TOXAV_FRIEND_CALL_STATE_ACCEPTING_V);\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A);\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_SHOW_VIDEO, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V);\n\n        {\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state == TOXAV_FRIEND_CALL_STATE_FINISHED);\n\n        printf(\"Success!\\n\");\n    }\n\n    if (TEST_STOP_RESUME_PAYLOAD) { /* Stop and resume audio/video payload */\n        printf(\"\\nTrying stop/resume functionality...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        /* Assume sending audio and video */\n        {\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        {\n            TOXAV_ERR_ANSWER rc;\n            toxav_answer(BobAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_ANSWER_OK) {\n                printf(\"toxav_answer failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        iterate_tox(bootstrap, Alice, Bob);\n\n        printf(\"Call started as audio only\\n\");\n        printf(\"Turning on video for Alice...\\n\");\n        ck_assert(toxav_bit_rate_set(AliceAV, 0, -1, 1000, NULL));\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state & TOXAV_FRIEND_CALL_STATE_SENDING_V);\n\n        printf(\"Turning off video for Alice...\\n\");\n        ck_assert(toxav_bit_rate_set(AliceAV, 0, -1, 0, NULL));\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(!(BobCC.state & TOXAV_FRIEND_CALL_STATE_SENDING_V));\n\n        printf(\"Turning off audio for Alice...\\n\");\n        ck_assert(toxav_bit_rate_set(AliceAV, 0, 0, -1, NULL));\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(!(BobCC.state & TOXAV_FRIEND_CALL_STATE_SENDING_A));\n\n        {\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state == TOXAV_FRIEND_CALL_STATE_FINISHED);\n\n        printf(\"Success!\\n\");\n    }\n\n    if (TEST_PAUSE_RESUME_SEND) { /* Stop and resume audio/video payload and test send options */\n        printf(\"\\nTrying stop/resume functionality...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        /* Assume sending audio and video */\n        {\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, Alice, Bob);\n\n        {\n            TOXAV_ERR_ANSWER rc;\n            toxav_answer(BobAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_ANSWER_OK) {\n                printf(\"toxav_answer failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        int16_t PCM[5670];\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(!toxav_audio_send_frame(AliceAV, 0, PCM, 960, 1, 48000, NULL));\n        ck_assert(!toxav_audio_send_frame(BobAV, 0, PCM, 960, 1, 48000, NULL));\n        ck_assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(toxav_audio_send_frame(AliceAV, 0, PCM, 960, 1, 48000, NULL));\n        ck_assert(toxav_audio_send_frame(BobAV, 0, PCM, 960, 1, 48000, NULL));\n        iterate_tox(bootstrap, Alice, Bob);\n\n        {\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                ck_assert(0);\n            }\n        }\n\n        iterate_tox(bootstrap, Alice, Bob);\n        ck_assert(BobCC.state == TOXAV_FRIEND_CALL_STATE_FINISHED);\n\n        printf(\"Success!\\n\");\n    }\n\n    toxav_kill(BobAV);\n    toxav_kill(AliceAV);\n    tox_kill(Bob);\n    tox_kill(Alice);\n    tox_kill(bootstrap);\n\n    printf(\"\\nTest successful!\\n\");\n}\nEND_TEST\n\n#ifndef HAVE_LIBCHECK\nint main(int argc, char *argv[])\n{\n    (void) argc;\n    (void) argv;\n\n    test_AV_flows();\n    return 0;\n}\n#else\nSuite *tox_suite(void)\n{\n    Suite *s = suite_create(\"ToxAV\");\n\n    DEFTESTCASE_SLOW(AV_flows, 200);\n    return s;\n}\nint main(int argc, char *argv[])\n{\n    (void) argc;\n    (void) argv;\n\n    Suite *tox = tox_suite();\n    SRunner *test_runner = srunner_create(tox);\n\n    setbuf(stdout, NULL);\n\n    srunner_run_all(test_runner, CK_NORMAL);\n    int number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n#endif\n"
  },
  {
    "path": "auto_tests/toxav_many_test.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#ifndef HAVE_LIBCHECK\n#   include <assert.h>\n\n#   define ck_assert(X) assert(X);\n#   define START_TEST(NAME) void NAME ()\n#   define END_TEST\n#else\n#   include \"helpers.h\"\n#endif\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n#include <vpx/vpx_image.h>\n\n#include \"../toxcore/tox.h\"\n#include \"../toxcore/util.h\"\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/crypto_core.h\"\n#include \"../toxav/toxav.h\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#include <pthread.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n\ntypedef struct {\n    bool incoming;\n    uint32_t state;\n} CallControl;\n\ntypedef struct {\n    ToxAV *AliceAV;\n    ToxAV *BobAV;\n    CallControl *AliceCC;\n    CallControl *BobCC;\n    uint32_t friend_number;\n} thread_data;\n\n/**\n * Callbacks\n */\nvoid t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)\n{\n    (void) av;\n    (void) audio_enabled;\n    (void) video_enabled;\n\n    printf(\"Handling CALL callback\\n\");\n    ((CallControl *)user_data)[friend_number].incoming = true;\n}\nvoid t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)\n{\n    printf(\"Handling CALL STATE callback: %d %p\\n\", state, av);\n    ((CallControl *)user_data)[friend_number].state = state;\n}\nvoid t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,\n                                    uint16_t width, uint16_t height,\n                                    uint8_t const *y, uint8_t const *u, uint8_t const *v,\n                                    int32_t ystride, int32_t ustride, int32_t vstride,\n                                    void *user_data)\n{\n    (void) av;\n    (void) friend_number;\n    (void) width;\n    (void) height;\n    (void) y;\n    (void) u;\n    (void) v;\n    (void) ystride;\n    (void) ustride;\n    (void) vstride;\n    (void) user_data;\n}\nvoid t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,\n                                    int16_t const *pcm,\n                                    size_t sample_count,\n                                    uint8_t channels,\n                                    uint32_t sampling_rate,\n                                    void *user_data)\n{\n    (void) av;\n    (void) friend_number;\n    (void) pcm;\n    (void) sample_count;\n    (void) channels;\n    (void) sampling_rate;\n    (void) user_data;\n}\nvoid t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    (void) userdata;\n\n    if (length == 7 && memcmp(\"gentoo\", data, 7) == 0) {\n        ck_assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);\n    }\n}\n\n\n/**\n * Iterate helper\n */\nToxAV *setup_av_instance(Tox *tox, CallControl *CC)\n{\n    TOXAV_ERR_NEW error;\n\n    ToxAV *av = toxav_new(tox, &error);\n    ck_assert(error == TOXAV_ERR_NEW_OK);\n\n    toxav_callback_call(av, t_toxav_call_cb, CC);\n    toxav_callback_call_state(av, t_toxav_call_state_cb, CC);\n    toxav_callback_video_receive_frame(av, t_toxav_receive_video_frame_cb, CC);\n    toxav_callback_audio_receive_frame(av, t_toxav_receive_audio_frame_cb, CC);\n\n    return av;\n}\nvoid *call_thread(void *pd)\n{\n    ToxAV *AliceAV = ((thread_data *) pd)->AliceAV;\n    ToxAV *BobAV = ((thread_data *) pd)->BobAV;\n    CallControl *AliceCC = ((thread_data *) pd)->AliceCC;\n    CallControl *BobCC = ((thread_data *) pd)->BobCC;\n    uint32_t friend_number = ((thread_data *) pd)->friend_number;\n\n\n    memset(AliceCC, 0, sizeof(CallControl));\n    memset(BobCC, 0, sizeof(CallControl));\n\n    { /* Call */\n        TOXAV_ERR_CALL rc;\n        toxav_call(AliceAV, friend_number, 48, 3000, &rc);\n\n        if (rc != TOXAV_ERR_CALL_OK) {\n            printf(\"toxav_call failed: %d\\n\", rc);\n            ck_assert(0);\n        }\n    }\n\n    while (!BobCC->incoming)\n        c_sleep(10);\n\n    { /* Answer */\n        TOXAV_ERR_ANSWER rc;\n        toxav_answer(BobAV, 0, 8, 500, &rc);\n\n        if (rc != TOXAV_ERR_ANSWER_OK) {\n            printf(\"toxav_answer failed: %d\\n\", rc);\n            ck_assert(0);\n        }\n    }\n\n    c_sleep(30);\n\n    int16_t PCM[960];\n    uint8_t video_y[800 * 600];\n    uint8_t video_u[800 * 600 / 2];\n    uint8_t video_v[800 * 600 / 2];\n\n    memset(PCM, 0, sizeof(PCM));\n    memset(video_y, 0, sizeof(video_y));\n    memset(video_u, 0, sizeof(video_u));\n    memset(video_v, 0, sizeof(video_v));\n\n    time_t start_time = time(NULL);\n\n    while (time(NULL) - start_time < 4) {\n        toxav_iterate(AliceAV);\n        toxav_iterate(BobAV);\n\n        toxav_audio_send_frame(AliceAV, friend_number, PCM, 960, 1, 48000, NULL);\n        toxav_audio_send_frame(BobAV, 0, PCM, 960, 1, 48000, NULL);\n\n        toxav_video_send_frame(AliceAV, friend_number, 800, 600, video_y, video_u, video_v, NULL);\n        toxav_video_send_frame(BobAV, 0, 800, 600, video_y, video_u, video_v, NULL);\n\n        c_sleep(10);\n    }\n\n    { /* Hangup */\n        TOXAV_ERR_CALL_CONTROL rc;\n        toxav_call_control(AliceAV, friend_number, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n        if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n            printf(\"toxav_call_control failed: %d %p %p\\n\", rc, AliceAV, BobAV);\n        }\n    }\n\n    c_sleep(30);\n\n    printf (\"Closing thread\\n\");\n    pthread_exit(NULL);\n}\n\n\nSTART_TEST(test_AV_three_calls)\n{\n    Tox *Alice, *bootstrap, *Bobs[3];\n    ToxAV *AliceAV, *BobsAV[3];\n\n    CallControl AliceCC[3], BobsCC[3];\n\n    {\n        TOX_ERR_NEW error;\n\n        bootstrap = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n\n        Alice = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n\n        Bobs[0] = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n\n        Bobs[1] = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n\n        Bobs[2] = tox_new(NULL, &error);\n        ck_assert(error == TOX_ERR_NEW_OK);\n    }\n\n    printf(\"Created 5 instances of Tox\\n\");\n    printf(\"Preparing network...\\n\");\n    long long unsigned int cur_time = time(NULL);\n\n    uint32_t to_compare = 974536;\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);\n    tox_self_get_address(Alice, address);\n\n\n    ck_assert(tox_friend_add(Bobs[0], address, (uint8_t *)\"gentoo\", 7, NULL) != (uint32_t) ~0);\n    ck_assert(tox_friend_add(Bobs[1], address, (uint8_t *)\"gentoo\", 7, NULL) != (uint32_t) ~0);\n    ck_assert(tox_friend_add(Bobs[2], address, (uint8_t *)\"gentoo\", 7, NULL) != (uint32_t) ~0);\n\n    uint8_t off = 1;\n\n    while (1) {\n        tox_iterate(bootstrap);\n        tox_iterate(Alice);\n        tox_iterate(Bobs[0]);\n        tox_iterate(Bobs[1]);\n        tox_iterate(Bobs[2]);\n\n        if (tox_self_get_connection_status(bootstrap) &&\n                tox_self_get_connection_status(Alice) &&\n                tox_self_get_connection_status(Bobs[0]) &&\n                tox_self_get_connection_status(Bobs[1]) &&\n                tox_self_get_connection_status(Bobs[2]) && off) {\n            printf(\"Toxes are online, took %llu seconds\\n\", time(NULL) - cur_time);\n            off = 0;\n        }\n\n        if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Alice, 1, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Alice, 2, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Bobs[0], 0, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Bobs[1], 0, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Bobs[2], 0, NULL) == TOX_CONNECTION_UDP)\n            break;\n\n        c_sleep(20);\n    }\n\n    AliceAV = setup_av_instance(Alice, AliceCC);\n    BobsAV[0] = setup_av_instance(Bobs[0], BobsCC + 0);\n    BobsAV[1] = setup_av_instance(Bobs[1], BobsCC + 1);\n    BobsAV[2] = setup_av_instance(Bobs[2], BobsCC + 2);\n\n    printf(\"Created 4 instances of ToxAV\\n\");\n    printf(\"All set after %llu seconds!\\n\", time(NULL) - cur_time);\n\n    thread_data tds[3];\n    tds[0].AliceAV = AliceAV;\n    tds[0].BobAV = BobsAV[0];\n    tds[0].AliceCC = AliceCC + 0;\n    tds[0].BobCC = BobsCC + 0;\n    tds[0].friend_number = 0;\n\n    tds[1].AliceAV = AliceAV;\n    tds[1].BobAV = BobsAV[1];\n    tds[1].AliceCC = AliceCC + 1;\n    tds[1].BobCC = BobsCC + 1;\n    tds[1].friend_number = 1;\n\n    tds[2].AliceAV = AliceAV;\n    tds[2].BobAV = BobsAV[2];\n    tds[2].AliceCC = AliceCC + 2;\n    tds[2].BobCC = BobsCC + 2;\n    tds[2].friend_number = 2;\n\n    pthread_t tids[3];\n    (void) pthread_create(tids + 0, NULL, call_thread, tds + 0);\n    (void) pthread_create(tids + 1, NULL, call_thread, tds + 1);\n    (void) pthread_create(tids + 2, NULL, call_thread, tds + 2);\n\n    (void) pthread_detach(tids[0]);\n    (void) pthread_detach(tids[1]);\n    (void) pthread_detach(tids[2]);\n\n    time_t start_time = time(NULL);\n\n    while (time(NULL) - start_time < 5) {\n        tox_iterate(Alice);\n        tox_iterate(Bobs[0]);\n        tox_iterate(Bobs[1]);\n        tox_iterate(Bobs[2]);\n        c_sleep(20);\n    }\n\n    (void) pthread_join(tids[0], NULL);\n    (void) pthread_join(tids[1], NULL);\n    (void) pthread_join(tids[2], NULL);\n\n    printf (\"Killing all instances\\n\");\n    toxav_kill(BobsAV[0]);\n    toxav_kill(BobsAV[1]);\n    toxav_kill(BobsAV[2]);\n    toxav_kill(AliceAV);\n    tox_kill(Bobs[0]);\n    tox_kill(Bobs[1]);\n    tox_kill(Bobs[2]);\n    tox_kill(Alice);\n    tox_kill(bootstrap);\n\n    printf(\"\\nTest successful!\\n\");\n}\nEND_TEST\n\n\n#ifndef HAVE_LIBCHECK\nint main(int argc, char *argv[])\n{\n    (void) argc;\n    (void) argv;\n\n    test_AV_three_calls();\n    return 0;\n}\n#else\nSuite *tox_suite(void)\n{\n    Suite *s = suite_create(\"ToxAV\");\n\n    TCase *tc_av_three_calls = tcase_create(\"AV_three_calls\");\n    tcase_add_test(tc_av_three_calls, test_AV_three_calls);\n    tcase_set_timeout(tc_av_three_calls, 150);\n    suite_add_tcase(s, tc_av_three_calls);\n\n    return s;\n}\n\nint main(int argc, char *argv[])\n{\n    (void) argc;\n    (void) argv;\n\n    Suite *tox = tox_suite();\n    SRunner *test_runner = srunner_create(tox);\n\n    setbuf(stdout, NULL);\n\n    srunner_run_all(test_runner, CK_NORMAL);\n    int number_failed = srunner_ntests_failed(test_runner);\n\n    srunner_free(test_runner);\n\n    return number_failed;\n}\n#endif\n"
  },
  {
    "path": "autogen.sh",
    "content": "#!/bin/sh -e\n\necho 'Running autoreconf -if...'\n(\n  autoreconf -if\n)\n"
  },
  {
    "path": "configure.ac",
    "content": "#                                               -*- Autoconf -*-\n# Process this file with autoconf to produce a configure script.\n\nAC_PREREQ([2.65])\nAC_INIT([tox], [0.0.0])\nAC_CONFIG_AUX_DIR(configure_aux)\nAC_CONFIG_SRCDIR([toxcore/net_crypto.c])\nAC_CONFIG_HEADERS([config.h])\nAM_INIT_AUTOMAKE([foreign 1.10 -Wall subdir-objects tar-ustar])\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])\nAC_CONFIG_MACRO_DIR([m4])\n\nEXTRA_LT_LDFLAGS=\n\nLIBTOXCORE_LT_VERSION=0:0:0\nLIBTOXAV_LT_VERSION=0:0:0\ndnl\ndnl            current:revision:age\ndnl\ndnl current:  increment if interfaces have been added, removed or changed\ndnl revision: increment if source code has changed, set to zero if current is\ndnl           incremented\ndnl age:      increment if interfaces have been added, set to zero if\ndnl           interfaces have been removed or changed\n\nif test \"x${prefix}\" = \"xNONE\"; then\n    prefix=\"${ac_default_prefix}\"\nfi\n\nBUILD_DHT_BOOTSTRAP_DAEMON=\"no\"\nBUILD_NTOX=\"no\"\nBUILD_TESTS=\"yes\"\nBUILD_AV=\"yes\"\nBUILD_TESTING=\"yes\"\n\nTOX_LOGGER=\"no\"\nLOGGING_OUTNAM=\"libtoxcore.log\"\n\nNCURSES_FOUND=\"no\"\nLIBCONFIG_FOUND=\"no\"\nLIBCHECK_FOUND=\"no\"\nWANT_NACL=\"no\"\nADD_NACL_OBJECTS_TO_PKGCONFIG=\"yes\"\n\nTOXCORE_LT_LDFLAGS=\"-version-info $LIBTOXCORE_LT_VERSION\"\nTOXAV_LT_LDFLAGS=\"-version-info $LIBTOXAV_LT_VERSION\"\n\nAC_ARG_ENABLE([soname-versions],\n    [AC_HELP_STRING([--enable-soname-versions], [enable soname versions (must be disabled for android) (default: enabled)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            TOXCORE_LT_LDFLAGS=\"-avoid-version\"\n            TOXAV_LT_LDFLAGS=\"-avoid-version\"\n        fi\n    ]\n)\n\nAC_SUBST(TOXCORE_LT_LDFLAGS)\nAC_SUBST(TOXAV_LT_LDFLAGS)\n\nAC_ARG_ENABLE([nacl],\n    [AC_HELP_STRING([--enable-nacl], [use nacl instead of libsodium (default: disabled)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            WANT_NACL=\"no\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            WANT_NACL=\"yes\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([randombytes-stir],\n    [AC_HELP_STRING([--enable-randombytes-stir], [use randombytes_stir() instead of sodium_init() for faster startup on android (default: disabled)]) ],\n    [\n        if test \"x$enableval\" = \"xyes\"; then\n            if test \"x$WANT_NACL\" = \"xyes\"; then\n                AC_MSG_WARN([randombytes_stir() is not available with NaCl library])\n            else\n                AC_DEFINE([USE_RANDOMBYTES_STIR], [1], [randombytes_stir() instead of sodium_init()])\n            fi\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([logging],\n    [AC_HELP_STRING([--enable-logging], [enable logging (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xyes\"; then\n            TOX_LOGGER=\"yes\"\n\n            AC_DEFINE([TOX_LOGGER], [], [If logging enabled])\n            AC_DEFINE([LOGGER_LEVEL], [LOG_DEBUG], [LOG_LEVEL value])\n            AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], [\"$LOGGING_OUTNAM\"], [Output of logger])\n        fi\n    ]\n)\n\nAC_ARG_WITH(log-level,\n    AC_HELP_STRING([--with-log-level=LEVEL],\n                   [Logger levels: TRACE; DEBUG; INFO; WARNING; ERROR ]),\n    [\n        if test \"x$TOX_LOGGER\" = \"xno\"; then\n            AC_MSG_WARN([Logging disabled!])\n        else\n            if test \"x$withval\" = \"xTRACE\"; then\n                AC_DEFINE([LOGGER_LEVEL], [LOG_TRACE], [LOG_LEVEL value])\n\n            elif test \"x$withval\" = \"xDEBUG\"; then\n                AC_DEFINE([LOGGER_LEVEL], [LOG_DEBUG], [LOG_LEVEL value])\n\n            elif test \"x$withval\" = \"xINFO\"; then\n                AC_DEFINE([LOGGER_LEVEL], [LOG_INFO], [LOG_LEVEL value])\n\n            elif test \"x$withval\" = \"xWARNING\"; then\n                AC_DEFINE([LOGGER_LEVEL], [LOG_WARNING], [LOG_LEVEL value])\n\n            elif test \"x$withval\" = \"xERROR\"; then\n                AC_DEFINE([LOGGER_LEVEL], [LOG_ERROR], [LOG_LEVEL value])\n            else\n                AC_MSG_WARN([Invalid logger level: $withval. Using default 'DEBUG'])\n            fi\n        fi\n    ]\n)\n\nAC_ARG_WITH(log-path,\n    AC_HELP_STRING([--with-log-path=DIR],\n                   [Path of logger output]),\n    [\n        if test \"x$TOX_LOGGER\" = \"xno\"; then\n            AC_MSG_WARN([Logging disabled!])\n        else\n            AC_DEFINE_UNQUOTED([LOGGER_OUTPUT_FILE], [\"$withval\"\"/\"\"$LOGGING_OUTNAM\"], [Output of logger])\n        fi\n    ]\n)\n\nPKG_PROG_PKG_CONFIG\n\nAC_ARG_ENABLE([av],\n    [AC_HELP_STRING([--disable-av], [build AV support libraries (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            BUILD_AV=\"no\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            BUILD_AV=\"yes\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([tests],\n    [AC_HELP_STRING([--disable-tests], [build unit tests (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            BUILD_TESTS=\"no\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            BUILD_TESTS=\"yes\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([ntox],\n    [AC_HELP_STRING([--enable-ntox], [build nTox client (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            BUILD_NTOX=\"no\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            BUILD_NTOX=\"yes\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([daemon],\n    [AC_HELP_STRING([--enable-daemon], [build DHT bootstrap daemon (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            BUILD_DHT_BOOTSTRAP_DAEMON=\"no\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            BUILD_DHT_BOOTSTRAP_DAEMON=\"yes\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([rt],\n    [AC_HELP_STRING([--disable-rt], [Disables the librt check (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            DISABLE_RT=\"yes\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            DISABLE_RT=\"no\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([testing],\n    [AC_HELP_STRING([--disable-testing], [build various testing tools (default: auto)]) ],\n    [\n        if test \"x$enableval\" = \"xno\"; then\n            BUILD_TESTING=\"no\"\n        elif test \"x$enableval\" = \"xyes\"; then\n            BUILD_TESTING=\"yes\"\n        fi\n    ]\n)\n\nAC_ARG_ENABLE([[epoll]],\n  [AS_HELP_STRING([[--enable-epoll[=ARG]]], [enable epoll support (yes, no, auto) [auto]])],\n    [enable_epoll=${enableval}],\n    [enable_epoll='auto']\n  )\n\nAX_HAVE_EPOLL\nif test \"$enable_epoll\" != \"no\"; then\n  if test \"${ax_cv_have_epoll}\" = \"yes\"; then\n    AC_DEFINE([TCP_SERVER_USE_EPOLL],[1],[define to 1 to enable epoll support])\n    enable_epoll='yes'\n  else\n    if test \"$enable_epoll\" = \"yes\"; then\n      AC_MSG_ERROR([[Support for epoll was explicitly requested but cannot be enabled on this platform.]])\n    fi\n    enable_epoll='no'\n  fi\nfi\n\nDEPSEARCH=\nLIBSODIUM_SEARCH_HEADERS=\nLIBSODIUM_SEARCH_LIBS=\nNACL_SEARCH_HEADERS=\nNACL_SEARCH_LIBS=\n\nAC_ARG_WITH(dependency-search,\n    AC_HELP_STRING([--with-dependency-search=DIR],\n                   [search for dependencies in DIR, i.e., look for libraries in\n                    DIR/lib and for headers in DIR/include]),\n    [\n        DEPSEARCH=\"$withval\"\n    ]\n)\n\nif test -n \"$DEPSEARCH\"; then\n    CFLAGS=\"$CFLAGS -I$DEPSEARCH/include\"\n    CPPFLAGS=\"$CPPFLAGS -I$DEPSEARCH/include\"\n    LDFLAGS=\"$LDFLAGS -L$DEPSEARCH/lib\"\n    export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$DEPSEARCH/lib/pkgconfig\nfi\n\nAC_ARG_WITH(nacl-headers,\n        AC_HELP_STRING([--with-nacl-headers=DIR],\n                       [search for nacl<F2> header files in DIR]),\n        [\n            NACL_SEARCH_HEADERS=\"$withval\"\n            AC_MSG_NOTICE([will search for nacl header files in $withval])\n        ]\n)\n\nAC_ARG_WITH(nacl-libs,\n        AC_HELP_STRING([--with-nacl-libs=DIR],\n                       [search for nacl libraries in DIR]),\n        [\n            NACL_SEARCH_LIBS=\"$withval\"\n            AC_MSG_NOTICE([will search for nacl libraries in $withval])\n        ]\n)\n\nAC_ARG_WITH(libsodium-headers,\n        AC_HELP_STRING([--with-libsodium-headers=DIR],\n                       [search for libsodium header files in DIR]),\n        [\n            LIBSODIUM_SEARCH_HEADERS=\"$withval\"\n            AC_MSG_NOTICE([will search for libsodium header files in $withval])\n        ]\n)\n\nAC_ARG_WITH(libsodium-libs,\n        AC_HELP_STRING([--with-libsodium-libs=DIR],\n                       [search for libsodium libraries in DIR]),\n        [\n            LIBSODIUM_SEARCH_LIBS=\"$withval\"\n            AC_MSG_NOTICE([will search for libsodium libraries in $withval])\n        ]\n)\n\nif test \"x$WANT_NACL\" = \"xyes\"; then\n    enable_shared=no\n    enable_static=yes\nfi\n\n# Checks for programs.\nAC_PROG_CC\nAM_PROG_CC_C_O\nm4_ifdef([AM_PROG_AR], [AM_PROG_AR])\nAC_LIBTOOL_WIN32_DLL\nAC_PROG_LIBTOOL\n\nWIN32=no\nMACH=no\nAC_CANONICAL_HOST\ncase $host_os in\n    *mingw*)\n        WIN32=\"yes\"\n        EXTRA_LT_LDFLAGS=\"$EXTRA_LT_LDFLAGS -no-undefined\"\n    ;;\n    *solaris*)\n        LIBS=\"$LIBS -lssp -lsocket -lnsl\"\n    ;;\n    *qnx*)\n        LIBS=\"$LIBS -lsocket\"\n    ;;\n    *freebsd*|*openbsd*)\n        LDFLAGS=\"$LDFLAGS -L/usr/local/lib\"\n        CFLAGS=\"$CFLAGS -I/usr/local/include\"\n        CPPFLAGS=\"$CPPFLAGS -I/usr/local/include\"\n        ADD_NACL_OBJECTS_TO_PKGCONFIG=\"no\"\n    ;;\n    darwin*)\n        MACH=yes\n    ;;\nesac\nAM_CONDITIONAL(WIN32, test \"x$WIN32\" = \"xyes\")\n\nAC_SUBST(EXTRA_LT_LDFLAGS)\n\n# Needed math flags for some compilers\n\nMATH_LDFLAGS=\"-lm\"\nAC_SUBST(MATH_LDFLAGS)\n\n# Checks for libraries.\n\nif test \"x$WANT_NACL\" = \"xyes\"; then\n    NACL_LIBS=\n    NACL_LDFLAGS=\n    NACL_OBJECTS=\n    NACL_OBJECTS_PKGCONFIG=\n    LDFLAGS_SAVE=\"$LDFLAGS\"\n    if test -n \"$NACL_SEARCH_LIBS\"; then\n        LDFLAGS=\"-L$NACL_SEARCH_LIBS $LDFLAGS\"\n        AC_CHECK_LIB(nacl, random,\n            [\n                NACL_LDFLAGS=\"-L$NACL_SEARCH_LIBS\"\n                NACL_LIBS=\"-lnacl\"\n            ],\n            [\n                AC_MSG_ERROR([library nacl was not found in requested location $NACL_SEARCH_LIBS])\n            ]\n        )\n    else\n        AC_CHECK_LIB(nacl, random,\n            [],\n            [\n                AC_MSG_ERROR([you enabled nacl support, but library nacl was not found on your system])\n            ]\n        )\n    fi\n\n    if (test -f \"$NACL_SEARCH_LIBS/cpucycles.o\") &&\n       (test -f \"$NACL_SEARCH_LIBS/randombytes.o\"); then\n        NACL_OBJECTS=\"$NACL_SEARCH_LIBS/cpucycles.o $NACL_SEARCH_LIBS/randombytes.o\"\n        if test \"x$ADD_NACL_OBJECTS_TO_PKGCONFIG\" = \"xyes\"; then\n            NACL_OBJECTS_PKGCONFIG=\"$NACL_OBJECTS\"\n        fi\n    else\n        AC_MSG_ERROR([required NaCl object files cpucycles.o randombytes.o not found, please specify their location using the --with-nacl-libs parameter])\n    fi\n\n    LDFLAGS=\"$LDFLAGS_SAVE\"\n    AC_SUBST(NACL_LIBS)\n    AC_SUBST(NACL_LDFLAGS)\n    AC_SUBST(NACL_OBJECTS)\n    AC_SUBST(NACL_OBJECTS_PKGCONFIG)\nelse\n    LIBSODIUM_LIBS=\n    LIBSODIUM_LDFLAGS=\n    LDFLAGS_SAVE=\"$LDFLAGS\"\n    if test -n \"$LIBSODIUM_SEARCH_LIBS\"; then\n        LDFLAGS=\"-L$LIBSODIUM_SEARCH_LIBS $LDFLAGS\"\n        AC_CHECK_LIB(sodium, crypto_pwhash_scryptsalsa208sha256,\n            [\n                LIBSODIUM_LDFLAGS=\"-L$LIBSODIUM_SEARCH_LIBS\"\n                LIBSODIUM_LIBS=\"-lsodium\"\n            ],\n            [\n                AC_MSG_ERROR([required library libsodium was not found in requested location $LIBSODIUM_SEARCH_LIBS or library version is too old])\n            ]\n        )\n    else\n        AC_CHECK_LIB(sodium, crypto_pwhash_scryptsalsa208sha256,\n            [],\n            [\n                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])\n            ]\n        )\n    fi\n\n    LDFLAGS=\"$LDFLAGS_SAVE\"\n    AC_SUBST(LIBSODIUM_LIBS)\n    AC_SUBST(LIBSODIUM_LDFLAGS)\nfi\n\n# Checks for header files.\nAC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h])\n\n\nif test \"x$WANT_NACL\" = \"xyes\"; then\n    NACL_CFLAGS=\n    CFLAGS_SAVE=\"$CFLAGS\"\n    CPPFLAGS_SAVE=\"$CPPFLAGS\"\n    if test -n \"$NACL_SEARCH_HEADERS\"; then\n        CFLAGS=\"-I$NACL_SEARCH_HEADERS $CFLAGS\"\n        CPPFLAGS=\"-I$NACL_SEARCH_HEADERS $CPPFLAGS\"\n        AC_CHECK_HEADER(crypto_box.h,\n            [\n                NACL_CFLAGS=\"-I$NACL_SEARCH_HEADERS\"\n            ],\n            [\n                AC_MSG_ERROR([header files for library nacl were not found in requested location $NACL_SEARCH_HEADERS])\n            ]\n        )\n    else\n        AC_CHECK_HEADER(crypto_box.h,\n            [],\n            [\n                AC_MSG_ERROR([you enabled nacl support, but nacl header files were not found on your system])\n            ]\n        )\n    fi\n    CFLAGS=\"$CFLAGS_SAVE\"\n    CPPFLAGS=\"$CPPFLAGS_SAVE\"\n    AC_SUBST(NACL_CFLAGS)\n    AC_DEFINE([VANILLA_NACL], [1], [use nacl instead of libsodium])\nelse\n    LIBSODIUM_CFLAGS=\n    CFLAGS_SAVE=\"$CFLAGS\"\n    CPPFLAGS_SAVE=\"$CPPFLAGS\"\n    if test -n \"$LIBSODIUM_SEARCH_HEADERS\"; then\n        CFLAGS=\"-I$LIBSODIUM_SEARCH_HEADERS $CFLAGS\"\n        CPPFLAGS=\"-I$LIBSODIUM_SEARCH_HEADERS $CPPFLAGS\"\n        AC_CHECK_HEADER(sodium.h,\n            [\n                LIBSODIUM_CFLAGS=\"-I$LIBSODIUM_SEARCH_HEADERS\"\n            ],\n            [\n                AC_MSG_ERROR([header files for required library libsodium were not found in requested location $LIBSODIUM_SEARCH_HEADERS])\n            ]\n        )\n    else\n        AC_CHECK_HEADER(sodium.h,\n            [],\n            [\n                AC_MSG_ERROR([header files for required library libsodium was not found on your system, please check http://download.libsodium.org/libsodium/releases/])\n            ]\n        )\n    fi\n    CFLAGS=\"$CFLAGS_SAVE\"\n    CPPFLAGS=\"$CPPFLAGS_SAVE\"\n    AC_SUBST(LIBSODIUM_CFLAGS)\nfi\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_HEADER_STDBOOL\nAC_TYPE_INT16_T\nAC_TYPE_INT32_T\nAC_TYPE_PID_T\nAC_TYPE_SIZE_T\nAC_TYPE_UINT16_T\nAC_TYPE_UINT32_T\nAC_TYPE_UINT64_T\nAC_TYPE_UINT8_T\nAC_C_BIGENDIAN\n\n\n# Checks for library functions.\nAC_FUNC_FORK\nAC_CHECK_FUNCS([gettimeofday memset socket strchr malloc])\nif (test \"x$WIN32\" != \"xyes\") && (test \"x$MACH\" != \"xyes\") && (test \"x${host_os#*openbsd}\" == \"x$host_os\") && (test \"x$DISABLE_RT\" != \"xyes\"); then\n    AC_CHECK_LIB(rt, clock_gettime,\n        [\n            RT_LIBS=\"-lrt\"\n            AC_SUBST(RT_LIBS)\n        ],\n        [\n            AC_MSG_ERROR([required library rt was not found on your system])\n        ]\n    )\nfi\n\n\nAX_PTHREAD(\n    [],\n    [\n        AC_MSG_ERROR([required library pthread was not found on your system])\n    ]\n)\n\nAC_CHECK_LIB([pthread], [pthread_self],\n    [\n        PTHREAD_LDFLAGS=\"-lpthread\"\n        AC_SUBST(PTHREAD_LDFLAGS)\n    ]\n)\n\nif test \"x$BUILD_AV\" = \"xyes\"; then\n    PKG_CHECK_MODULES([OPUS], [opus],\n        [],\n        [\n            AC_MSG_WARN([disabling AV support $OPUS_PKG_ERRORS])\n            BUILD_AV=\"no\"\n        ]\n    )\nfi\n\nif test \"x$BUILD_AV\" = \"xyes\"; then\n    PKG_CHECK_MODULES([VPX], [vpx],\n        [],\n        [\n            AC_MSG_WARN([disabling AV support $VPX_PKG_ERRORS])\n            BUILD_AV=\"no\"\n        ]\n    )\nfi\n\nif test \"x$BUILD_AV\" = \"xyes\"; then\n    # toxcore lib needs an global?\n    # So far this works okay\n    AV_LIBS=\"$OPUS_LIBS $VPX_LIBS\"\n    AC_SUBST(AV_LIBS)\n\n    AV_CFLAGS=\"$OPUS_CFLAGS $VPX_CFLAGS\"\n    AC_SUBST(AV_CFLAGS)\nfi\n\nif test -n \"$PKG_CONFIG\"; then\n    if test \"x$BUILD_TESTS\" = \"xyes\"; then\n        PKG_CHECK_MODULES([CHECK], [check],\n            [\n                LIBCHECK_FOUND=\"yes\"\n            ],\n            [\n                AC_MSG_WARN([libcheck not found, not building unit tests: $CHECK_PKG_ERRORS])\n                BUILD_TESTS=\"no\"\n            ])\n    fi\n\n    if test \"x$BUILD_DHT_BOOTSTRAP_DAEMON\" = \"xyes\"; then\n        PKG_CHECK_MODULES([LIBCONFIG], [libconfig >= 1.4.6],\n            [\n                LIBCONFIG_FOUND=\"yes\"\n            ],\n            [\n                AC_MSG_WARN([$LIBCONFIG_PKG_ERRORS])\n                AC_MSG_WARN([libconfig not available, will not build DHT bootstrap daemon])\n                BUILD_DHT_BOOTSTRAP_DAEMON=\"no\"\n            ])\n    fi\n\n    if test \"x$BUILD_NTOX\" = \"xyes\"; then\n        PKG_CHECK_MODULES([NCURSES], [ncurses],\n            [\n                NCURSES_FOUND=\"yes\"\n            ],\n            [\n                AC_MSG_WARN([$NCURSES_PKG_ERRORS])\n            ])\n    fi\nelse\n    AC_MSG_WARN([pkg-config was not found on your system, will search for libraries manually])\nfi\n\nif (test \"x$BUILD_NTOX\" = \"xyes\") && (test \"x$NCURSES_FOUND\" != \"xyes\"); then\n    AC_PATH_PROG([CURSES_CONFIG], [ncurses5-config], [no])\n    if test \"x$CURSES_CONFIG\" != \"xno\"; then\n        AC_MSG_CHECKING(ncurses cflags)\n        NCURSES_CFLAGS=`${CURSES_CONFIG} --cflags`\n        AC_MSG_RESULT($NCURSES_CFLAGS)\n\n        AC_MSG_CHECKING(ncurses libraries)\n        NCURSES_LIBS=`${CURSES_CONFIG} --libs`\n        AC_MSG_RESULT($NCURSES_LIBS)\n\n        AC_SUBST(NCURSES_CFLAGS)\n        AC_SUBST(NCURSES_LIBS)\n        NCURSES_FOUND=\"yes\"\n    fi\n\n    if test \"x$NCURSES_FOUND\" != \"xyes\"; then\n        AC_CHECK_HEADER([curses.h],\n            [],\n            [\n                AC_MSG_WARN([not building nTox client because headers for the curses library were not found on your system])\n                BUILD_NTOX=\"no\"\n            ]\n        )\n        if test \"x$BUILD_NTOX\" = \"xyes\"; then\n            if test \"x$WIN32\" = \"xyes\"; then\n                AC_CHECK_LIB([pdcurses], [clear],\n                    [\n                        NCURSES_LIBS=\"-lpdcurses\"\n                        AC_SUBST(NCURSES_LIBS)\n                    ],\n                    [\n                        AC_MSG_ERROR([required library pdcurses was not found on your system])\n                        BUILD_NTOX=\"no\"\n                    ]\n                )\n            else\n                AC_CHECK_LIB([ncurses], [clear],\n                    [\n                        NCURSES_LIBS=\"-lncurses\"\n                        AC_SUBST(NCURSES_LIBS)\n                    ],\n                    [\n                        unset ac_cv_lib_ncurses_clear\n                        AC_CHECK_LIB([ncurses], [clear],\n                            [\n                                NCURSES_LIBS=\"-lncurses -ltinfo\"\n                                AC_SUBST(NCURSES_LIBS)\n                            ],\n                            [\n                                AC_MSG_WARN([not building nTox client because required library ncurses was not found on your system])\n                                BUILD_NTOX=\"no\"\n                            ],\n                            [\n                                -ltinfo\n                            ]\n                        )\n                    ]\n                )\n            fi\n        fi\n    fi\nfi\n\nif (test \"x$BUILD_DHT_BOOTSTRAP_DAEMON\" = \"xyes\") && \\\n   (test \"x$LIBCONFIG_FOUND\" = \"xno\"); then\n    AC_CHECK_HEADER(libconfig.h,\n        [],\n        [\n            AC_MSG_WARN([header files for library libconfig was not found on your system, not building DHT bootstrap daemon])\n            BUILD_DHT_BOOTSTRAP_DAEMON=\"no\"\n        ]\n    )\n\n    if test \"x$BUILD_DHT_BOOTSTRAP_DAEMON\" = \"xyes\"; then\n        AC_CHECK_LIB(config, config_read,\n            [],\n            [\n                AC_MSG_WARN([library libconfig was not found on the system])\n                BUILD_DHT_BOOTSTRAP_DAEMON=\"no\"\n            ]\n        )\n    fi\nfi\n\nif (test \"x$BUILD_TESTS\" = \"xyes\") && (test \"x$LIBCHECK_FOUND\" = \"xno\"); then\n    AC_CHECK_HEADER([check.h],\n        [],\n        [\n            AC_MSG_WARN([header file for check library was not found on your system, unit tests will be disabled])\n            BUILD_TESTS=\"no\"\n        ]\n    )\n\n    if test \"x$BUILD_TESTS\" = \"xyes\"; then\n        AC_CHECK_LIB([check], [suite_create],\n            [],\n            [\n                AC_MSG_WARN([library check was not found on the system, unit tests will be disabled])\n                BUILD_TESTS=\"no\"\n            ]\n       )\n    fi\nfi\n\nif test \"x$WIN32\" = \"xyes\"; then\n    AC_CHECK_LIB(ws2_32, main,\n        [\n            WINSOCK2_LIBS=\"-liphlpapi -lws2_32\"\n            AC_SUBST(WINSOCK2_LIBS)\n        ],\n        [\n            AC_MSG_ERROR([required library was not found on the system, please check your MinGW installation])\n        ]\n    )\nfi\n\nAM_CONDITIONAL(BUILD_DHT_BOOTSTRAP_DAEMON, test \"x$BUILD_DHT_BOOTSTRAP_DAEMON\" = \"xyes\")\nAM_CONDITIONAL(BUILD_TESTS, test \"x$BUILD_TESTS\" = \"xyes\")\nAM_CONDITIONAL(BUILD_NTOX, test \"x$BUILD_NTOX\" = \"xyes\")\nAM_CONDITIONAL(BUILD_AV, test \"x$BUILD_AV\" = \"xyes\")\nAM_CONDITIONAL(BUILD_TESTING, test \"x$BUILD_TESTING\" = \"xyes\")\nAM_CONDITIONAL(WITH_NACL, test \"x$WANT_NACL\" = \"xyes\")\nAM_CONDITIONAL(WIN32, test \"x$WIN32\" = \"xyes\")\n\nAC_CONFIG_FILES([Makefile\n                 build/Makefile\n                 libtoxcore.pc\n                 tox.spec\n                ])\n\nAM_COND_IF(BUILD_AV,\n  [\n    AC_CONFIG_FILES([libtoxav.pc])\n  ],)\n\nAC_OUTPUT\n"
  },
  {
    "path": "dist-build/android-arm.sh",
    "content": "#!/bin/sh\nexport CFLAGS=\"-Ofast -mthumb -marm -march=armv6\"\nTARGET_ARCH=arm TOOLCHAIN_NAME=arm-linux-androideabi-4.8 HOST_COMPILER=arm-linux-androideabi \"$(dirname \"$0\")/android-build.sh\"\n"
  },
  {
    "path": "dist-build/android-armv7.sh",
    "content": "#!/bin/sh\nexport CFLAGS=\"-Ofast -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -marm -march=armv7-a\"\nTARGET_ARCH=armv7 TOOLCHAIN_NAME=arm-linux-androideabi-4.8 HOST_COMPILER=arm-linux-androideabi \"$(dirname \"$0\")/android-build.sh\"\n"
  },
  {
    "path": "dist-build/android-build.sh",
    "content": "#!/bin/sh\n\nif [ -z \"$ANDROID_NDK_HOME\" ]; then\n    echo \"You should probably set ANDROID_NDK_HOME to the directory containing\"\n    echo \"the Android NDK\"\n    exit\nfi\n\nif [ -z \"$SODIUM_HOME\" ]; then\n    echo \"You should probably set SODIUM_HOME to the directory containing root sodium sources\"\n    exit\nfi\n\nif [[ -z $TARGET_ARCH ]] || [[ -z $HOST_COMPILER ]]; then\n    echo \"You shouldn't use android-build.sh directly, use android-[arch].sh instead\"\n    exit 1\nfi\n\nif [ ! -f ./configure ]; then\n\techo \"Can't find ./configure. Wrong directory or haven't run autogen.sh?\"\n\texit 1\nfi\n\nif [ -z \"$TOOLCHAIN_DIR\" ]; then\n  export TOOLCHAIN_DIR=\"$(pwd)/android-toolchain-${TARGET_ARCH}\"\n  export MAKE_TOOLCHAIN=\"${ANDROID_NDK_HOME}/build/tools/make-standalone-toolchain.sh\"\n  \n  if [ -z \"$MAKE_TOOLCHAIN\" ]; then\n    echo \"Cannot find a make-standalone-toolchain.sh in ndk dir, interrupt...\"\n    exit 1\n  fi\n  \n  $MAKE_TOOLCHAIN --platform=\"${NDK_PLATFORM:-android-14}\" \\\n                  --arch=\"${TARGET_ARCH}\" \\\n                  --toolchain=\"${TOOLCHAIN_NAME:-arm-linux-androideabi-4.8}\" \\\n                  --install-dir=\"${TOOLCHAIN_DIR}\"\nfi\n\nexport PREFIX=\"$(pwd)/toxcore-android-${TARGET_ARCH}\"\nexport SYSROOT=\"${TOOLCHAIN_DIR}/sysroot\"\nexport PATH=\"${PATH}:${TOOLCHAIN_DIR}/bin\"\n\n# Clean up before build\nrm -rf \"${PREFIX}\"\n\nexport CFLAGS=\"${CFLAGS} --sysroot=${SYSROOT} -I${SYSROOT}/usr/include\"\nexport CPPFLAGS=\"${CFLAGS}\"\nexport LDFLAGS=\"${LDFLAGS} -L${SYSROOT}/usr/lib\"\n\n./configure --host=\"${HOST_COMPILER}\" \\\n            --with-sysroot=\"${SYSROOT}\" \\\n            --with-libsodium-headers=\"${SODIUM_HOME}/libsodium-android-${TARGET_ARCH}/include\" \\\n            --with-libsodium-libs=\"${SODIUM_HOME}/libsodium-android-${TARGET_ARCH}/lib\" \\\n            --disable-av \\\n            --prefix=\"${PREFIX}\" && \\\n\nmake clean && \\\nmake -j3 install && \\\necho \"libtoxcore has been installed into ${PREFIX}\"\n"
  },
  {
    "path": "dist-build/android-mips.sh",
    "content": "#!/bin/sh\nexport CFLAGS=\"-Ofast\"\nTARGET_ARCH=mips TOOLCHAIN_NAME=mipsel-linux-android-4.8 HOST_COMPILER=mipsel-linux-android \"$(dirname \"$0\")/android-build.sh\"\n"
  },
  {
    "path": "dist-build/android-x86.sh",
    "content": "#!/bin/sh\nexport CFLAGS=\"-Ofast\"\nTARGET_ARCH=x86 TOOLCHAIN_NAME=x86-4.8 HOST_COMPILER=i686-linux-android \"$(dirname \"$0\")/android-build.sh\"\n"
  },
  {
    "path": "docs/Group-Chats.md",
    "content": "Group chats.\n\nNote: we assume everyone in the chat trusts each other.\n\nThese group chats work by temporarily adding the 4 \"closest\" people defined by a distance function \nin group.c in order to form a circle of connected peers. These peers then relay messages to each other.\n\nA friend invites another friend to a group chat by sending them an invite packet. The friend either ignores \nthe invite or responds with a response packet if he wants to join the chat. The friend invite contains the type\nof groupchat (text only, A/V) the friend is being invited to.\n\n\nTODO: write more of this.\n\n## Protocol\n\nInvite packets:\nInvite packet:\n[uint8_t id 96][uint8_t id 0][uint16_t group chat number][33 bytes group chat identifier[1 byte type][32 bytes id]]\n\nResponse packet\n[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]]\n\n\nPeer online packet:\n[uint8_t id 97][uint16_t group chat number (local)][33 bytes group chat identifier[1 byte type][32 bytes id]]\n\nPeer leave packet:\n[uint8_t id 98][uint16_t group chat number][uint8_t id 1]\n\nPeer query packet:\n[uint8_t id 98][uint16_t group chat number][uint8_t id 8]\n\nPeer response packet:\n[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]] \n\nTitle response packet:\n[uint8_t id 98][uint16_t group chat number][uint8_t id 10][title]\n\nMessage packets:\n[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]\n\nLossy Message packets:\n[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]\n\nGroup chat types:\n0: text\n1: AV\n\n\nNote: the message number is increased by 1 for each sent message.\n\nmessage ids:\n0 - ping\nsent every ~60 seconds by every peer.\nNo data.\n\n16 - new_peer\nTell everyone about a new peer in the chat.\n[uint16_t peer_num][uint8_t 32bytes real public key][uint8_t 32bytes temp DHT public key]\n\n17 - kill_peer\n[uint16_t peer_num]\n\n48 - name change\n[uint8_t name[namelen]]\n\n49 - groupchat title change\n[uint8_t title[titlelen]]\n\n64 - chat message\n[uint8_t message[messagelen]]\n\n65 - action (/me)\n[uint8_t message[messagelen]]\n\n\n\n"
  },
  {
    "path": "docs/Hardening.txt",
    "content": "Currently an attacker with sufficient resources could launch a large scale \ndenial of service type attack by flooding the Tox network with a bunch of nodes \nthat do not act like real nodes to prevent people from finding each other. \n\nDue to the design of Tox, this is the worst thing an attacker can do to disrupt \nthe network.\n\nThis solution's goal is to make these denial of service attack very very hard \nto accomplish.\n\nFor the network to work every Tox node must:\n1. Respond to ping requests.\n2. Respond to get node requests with the ids of nodes closest to a queried id \n(It is assumed each nodes know at least the 32 nodes closest to them.)\n3. Properly send crypto request packets to their intended destination.\n\nCurrently the only thing a node needs to do to be part of the network is \nrespond correctly to ping requests. \n\nThe only people we really trust on the network are the nodes in our friends \nlist.\n\n\nThe behavior of each Tox node is easily predictable. This means that it possible \nfor Tox nodes to test the nodes that they are connected to to see if they \nbehave like normal Tox nodes and only send nodes that are confirmed to behave \nlike real Tox nodes as part of send node replies when other nodes query them.\n\nIf correctly done, this means that to poison the network an attacker can only \ninfiltrate the network if his \"fake\" nodes behave exactly like real nodes \ncompletely defeating the purpose of the attack. Of course nodes must be \nrechecked regularly to defeat an attack where someone floods the network with \nmany good nodes then suddenly turns them all bad.\n\nThis also prevents someone from accidentally killing the tox network with a bad \nimplementation of the protocol.\n\nImplementation ideas (In Progress):\n\n1. Use our friends to check if the nodes in our close list are good.\n\nEX: If our friend queries a node close to us and it correctly returns our \nip/port and then sends a crypto request packet to it and it routes it correctly \nto us then it is good.\n\nProblems with this: People don't always have at least one online friend.\n\n2. Pick random nodes (add ourselves some random (fake) friends to increase the \npool of available nodes) and make then send requests to other nodes, the \nresponse is then relayed back to us and compared to how the node should have \nbehaved. If the node is found to be behaving correctly, it is set as trusted. \nOnly trusted nodes are sent in send node packets, that is unless the exact node \nbeing queried for in the getnode packet is present, it will be sent in the \nsendnode packet even if it is not trusted.\n\nThe hypothesis is that if to be part of the network nodes have to behave \ncorrectly it should prevent disruption from nodes that behave incorrectly.\n\n(This idea is currently being implemented in the harden branch.)\n...\n"
  },
  {
    "path": "docs/Hardening_docs.txt",
    "content": "Hardening request packets are sent as crypto request packets (see crypto docs.)\nNOTE: currently only get nodes requests are tested in the code which is why \nthere is only one test (more will be added soon.)\n\nAll hardening requests must contain exactly 768 bytes of data. (The data sent \nmust be padded with zeros if it is smaller than that.)\n\n1. Get the information (IP_port, client_id) of the node we want to test.\n2. Find a couple random nodes that is not that node (one for each test.)\n3. Send crypto request packets to each of these random nodes with the data being:\n\n[byte with value: 02 (get nodes test request)][struct Node_format (the node to \ntest.)][client_id(32 bytes) the id to query the node with.][padding]\n\n4. The random node receives a packet.\n-The packet is a get nodes test request:\n    send a get_node request to that node with the id to query in the request.\n    when a send_node response is received, send the following response to the \n\tperson who sent us the get nodes test request packet:\n        [byte with value: 03 (get nodes test response)][client_id(32 bytes): \n\t\tthe id of the tested node][The list of nodes it responded with in IPv6 \n\t\tNode format (struct Node_Format)]\n    PROTIP: (get node requests and response contain an encrypted part that you \n\tcan use to store information so that you don't \n    have to store in your memory where/if to send back the response from the \n\tsend node)\n\n5. Receive the test responses.\n-If the test(s) pass (the nodes behave in a satisfactory manner), make these \nnodes have priority over those who don't pass the test(s).\n"
  },
  {
    "path": "docs/Prevent_Tracking.txt",
    "content": "Current privacy issues with the Tox DHT: \n\n1. It makes tracking people across different IPs very easy.\nSolution: Have each new DHT use a temporary public/private key pair not related \nto the long term public/private key pair.\n\n2. Metadata on which key is friends to which can be collected (The hardening \nmakes this somewhat harder by introducing a bunch of random traffic but not \nimpossible.).\nSolution: If no long term keys were used in the DHT it would solve this \nproblem. (possibly knowing which ip is connected to which is much less \nprecious.)\n\n\nSo, it seems all our privacy problems are solved if we can manage to make every \nnode in the DHT have a keypair that is not related to the long term keys and is \ngenerated every session.\n\n\nSo, every node in the DHT now has a temporary keypair not related to their real \nlong term one. \n\nBut, how do people find themselves then? We have to add a way for people to \ntell their friends what their DHT public key is. We also have to somehow make \nit so people can send/receive friend requests. This has to be done without \nnon-friends being able to find out where a node is.\n\nThe solution: Onion routing + enable the storage of some small amount of data \non DHT nodes.\n\n\nAlice and bob are friends. Before joining the DHT they generate temporary \nsession keypairs to be used for the DHT instead of their long term keys.\n\nBob finds a bunch of random nodes then picks 3 random working ones (A, B, C).\n\nBob gets the known working node with an id closest to his real one from his list (D)\n\nBob then creates an onion (the packet will go through A, B, C and will end up at D) \nannounce request packet with his real public key, ping_id as zeros and\nsearching for his real public key.\n\nBob will announce response packets and will recursively send onion announce request \npackets to closer and closer nodes until he finds the ones closest to his real public key.\n\nOnce he has done this, he will send some onion announce request packets with the right \nping_id previously received from the node when he queried it to announce himself to the node.\n\nThe nodes he announces himself to keep the information to send onion packets to that node in \nmemory.\n\nAlice meanwhile searches for the nodes closest to Bobs real id using a temporary keypair and \nannounce request packets. She does this until she finds nodes that respond with a ping_id of zero.\n\nShe sends data to route request packet with information telling Bob her temporary id in the DHT\n(or a friend request if she is not friends with him).\n\nBob finds her by using her temporary id and they connect to each other.\n\n\nNOTE: crypto_box is used for all the asymmetric encryption and crypto_secretbox is used for all \nthe symmetric. Also every DHT node have a random symmetric key which they use to encrypt the stuff \nin normal get node request that is used to encrypt stuff in the following.\n\nOnion packet (request):\n\ninitial (sent from us to node A):\n\n[uint8_t packet id (128)][nonce]\n[our temp DHT public key]encrypted with our temp DHT private key and the pub key of Node A and the nonce:[ \n[IP_Port of node B][a random public key]encrypted with the random private key and the pub key of Node B and the nonce:[ \n[IP_Port of node C][a random public key]encrypted with the random private key and the pub key of Node C and the nonce:[ \n[IP_Port of node D][data to send to Node D]]]]\n\n(sent from node A to node B):\n\n[uint8_t packet id (129)][nonce]\n[a random public key]encrypted with the random private key and the pub key of Node B and the nonce:[ \n[IP_Port of node C][a random public key]encrypted with the random private key and the pub key of Node C and the nonce:[ \n[IP_Port of node D][data to send to Node D]]][nonce (for the following symmetric encryption)]encrypted with temp symmetric key of Node A: [IP_Port (of us)]\n\n(sent from node B to node C):\n\n[uint8_t packet id (130)][nonce]\n[a random public key]encrypted with the random private key and the pub key of Node C and the nonce:[ \n[IP_Port of node D][data to send to Node D]][nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node B:[IP_Port (of Node A)[nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node A: [IP_Port (of us)]]\n\n(sent from node C to node D):\n[data to send to Node D][nonce (for the following symmetric encryption)]encrypted with temp symmetric key of Node C:\n[IP_Port (of Node B)[nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node B:[IP_Port (of Node A)[nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node A: [IP_Port (of us)]]]\n\nData sent to Node D:\n\nannounce request packet:\n[uint8_t packet id (131)][nonce][our real long term public key or a temporary one (see next)]\nencrypted (with our real long term private key if we want to announce ourselves, a temporary one if we are searching for friends) and the pub key of Node D and the nonce:\n[[(32 bytes) ping_id][client id we are searching for][public key that we want those sending back data packets to use.][data to send back in response(fixed size)]]\n\n(if the ping id is zero, respond with a announce response packet)\n(If the ping id matches the one the node sent in the announce response and the public key matches the one being searched for, \nadd the part used to send data to our list (if the list is full make it replace the furthest entry))\n\ndata to route request packet:\n[uint8_t packet id (133)][public key of destination node][nonce][temporary just generated public key]\nencrypted with that temporary private key and the nonce and the public key from the announce response packet of the destination node:[data]\n(if Node D contains the ret data for the node, it sends the stuff in this packet as a data to route response packet to the right node)\n\nThe data in the previous packet is in format: [real public key of sender]\nencrypted with real private key of the sender, the nonce in the data packet and\nthe real public key of the receiver:[[uint8_t id][data (optional)]]\n\nData sent to us:\nannounce response packet:\n[uint8_t packet id (132)][data to send back in response(fixed size)][nonce]\nencrypted with the DHT private key of Node D, the public key in the request and the nonce:[[uint8_t is_stored]\n[(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)]]\n(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)\nis_stored is 2 as a response to a peer trying to announce himself to tell the\npeer that he is currently announced successfully.\n\ndata to route response packet:\n[uint8_t packet id (134)][nonce][temporary just generated public key]\nencrypted with that temporary private key, the nonce and the public key from the announce response packet of the destination node:[data]\n\n\nOnion packet (response):\n\ninitial (sent from node D to node C):\n\n[uint8_t packet id (140)][nonce (for the following symmetric encryption)]encrypted with temp symmetric key of Node C:\n[IP_Port (of Node B)[nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node B:[IP_Port (of Node A)[nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node A: [IP_Port (of us)]]][data to send back]\n\n(sent from node C to node B):\n\n[uint8_t packet id (141)][nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node B:[IP_Port (of Node A)[nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node A: [IP_Port (of us)]][data to send back]\n\n(sent from node B to node A):\n\n[uint8_t packet id (142)][nonce (for the following symmetric encryption)]\nencrypted with temp symmetric key of Node A: [IP_Port (of us)][data to send back]\n\n(sent from node A to us):\n\n[data to send back]\n\n\nData packets:\n\nTo tell our friend what our DHT public key is so that he can connect to us we send a data packet \nwith id 156 and the data being:[uint64_t (in network byte order) no_replay, the packet will only be \naccepted if this number is bigger than the last one received] [our dht public key][Node_Format * (\nmaximum of 8) nodes closest to us so that the friend can find us faster]\n"
  },
  {
    "path": "docs/TCP_Network.txt",
    "content": "It has come to our attention that to achieve decent market penetration Tox \nmust work behind ALL internet connections, may they be behind enterprise NATs \nor any other bad network conditions. \n\nThe people who have issues with the UDP direct connection approach seem to be a \nsmall minority though it is hard to estimate how many.\n\nThis means that routing their packets using good nodes on the network will \nprobably not take a huge toll on the network and will assure that people\ncan use Tox regardless of the quality of their internet connection.\n\n\nHow it's going to work:\n1. Alice, a Tox client on a TCP only network generates a temporary public key \nand connects to a bootstrap node.\n\n2. Using the bootstrap node she finds and connects to a couple (exact number \nto be determined later) number of random nodes that have TCP relay support.\n\n3. She uses the onion through the TCP relay connections to send friend requests \nor tell online friends which TCP nodes she is connected to and her temporary \npublic key.\n\n4. Bob receives an onion packet from Alice telling him which nodes she is \nconnected to. Bob connects to these nodes and establishes a routed connection \nwith alice using that temporary public key.\n\n5. That connection is used by both to transmit encrypted Messenger and A/V \npackets.\n\n6. If one of the nodes shuts down while it is currently routing traffic, Alice \nand bob just switch to one of the other nodes they are both connected to.\n\n\nDetailed implementation details:\n\nThere are two distinct parts for TCP relays, the client part and the server \npart.\n\nThe server acts as the actual relay. Servers must have fully forwarded TCP \nports (NAT-PMP and uPNP can help here). The first port the server will try \nbinding to is 443 followed by port 3389 and possibly some others. Onion packets \ncan be sent/received through the TCP servers.\n\n\nServer:\n\nThe public/private key pair the TCP server uses is the same one he uses for the \nDHT. \n\nall crypto for communication with the server uses the crypto_box() function of \nNaCl.\n\nTCP doesn't have packets so what we will refer to as packets are sent this way: \n[[uint16_t (length of data)][data]]\n\nSo if you would inspect the TCP stream you would see:\n[[uint16_t (length of data)][data]][[uint16_t (length of \ndata)][data]][[uint16_t (length of data)][data]]\n\nNote that both handshake packets don't have this format (the length for them is \nalways the same so we don't need to specify it.)\n\nWhen the client connects to the server, he sends this packet:\n[public key of client (32 bytes)][nonce for the encrypted data [24 \nbytes]][encrypted with the private key of the client and public key of the \nserver and the nonce:[public key (32 bytes) and][base nonce we want the server \nto use to encrypt the packets sent to us (24 bytes)]]\n\nThe server responds with:\n[nonce for the encrypted data [24 bytes]][encrypted with the public key of the \nclient and private key of the server and the nonce:[public key (32 bytes) \nand][base nonce we want the client to use to encrypt the packets sent to us (24 \nbytes)]]\n\nAll packets to the server are end to end encrypted with the information \nreceived \n(and sent) in the handshake.\n\n(first packet is encrypted with the base nonce the private key for which the \nclient sent the server the public key and the public key we sent to the client, \nthe next with base nonce + 1...)\n\nThe connection is set to an unconfirmed state until a packet is received and \ndecrypted correctly using the information in the handshake.\n\neach packet sent to/from the server has an id (the first byte of the plain text \ndata of the packet.)\n\nids 0 to 15 are reserved for special packets, ids 16 to 255 are used to denote \nwho we want the data to be routed to/who the packet is from.\n\nspecial ids and packets:\n0 - Routing request.\n[uint8_t id (0)][public key (32 bytes)]\n1 - Routing request response.\n[uint8_t id (1)][uint8_t (rpid) 0 if refused, packet id if accepted][public key \n(32 bytes)]\n2 - Connect notification:\n[uint8_t id (2)][uint8_t (packet id of connection that got connected)]\n3 - Disconnect notification:\n[uint8_t id (3)][uint8_t (packet id of connection that got disconnected)]\n4 - ping packet\n[uint8_t id (4)][uint64_t ping_id (0 is invalid)]\n5 - ping response (pong)\n[uint8_t id (5)][uint64_t ping_id (0 is invalid)]\n6 - OOB send\n[uint8_t id (6)][destination public key (32 bytes)][data]\n7 - OOB recv\n[uint8_t id (7)][senders public key (32 bytes)][data]\n8 - onion packet (same format as initial onion packet (See: Prevent \ntracking.txt) but packet id is 8 instead of 128)\n9 - onion packet response (same format as onion packet with id 142 but id is 9 \ninstead.)\n\nThe rest of the special ids are reserved for possible future usage.\n\nIf the server receives a routing request he stores server side that the client \nwants to connect to the person with that public key and sends back a Routing \nrequest response with the rpid along with the public key sent in the request.\n\nIf for some reason the server must refuse the routing request (too many) he \nsends the response with a rpid of 0.\n\nIf the person who the client wants to connect to is also online and wants to \nconnect to the client a connect notification is sent to both with the \nappropriate packet id.\n\nIf either one disconnects, a disconnect notification is sent to the other with \nappropriate packet id.\n\nIf a client sends a disconnect notification, the entry on the server for that \nrouted connection is cleared and a disconnect notification is sent to the peer \n(if he was online)\n\nIf the server receives an onion packet he handles it the same as he would if it \nwas one received normally via UDP, he must also assure himself that any \nresponses must be sent to the proper client.\n\nPing responses must have the same ping_id as the request.\n\nIf the server receives a ping packet he must respond with a ping response.\n\nThe server will send a ping packet to clients every 30 seconds, they have 30 \nseconds to respond, if they don't the connection is deleted.\n\nOOB send packets will be sent to the peer connected to the TCP server with the \ndestination public key as a OOB recv packet. The client sending this packet has \nno way of knowing if the packet reached its destination.\n\n\nClient:\n\nImplementation details coming soon.\n"
  },
  {
    "path": "docs/TODO.md",
    "content": "# Toxcore todo list.\nWelcome to the Toxcore todo list, this is very likely out of date, but either way it's a good jumping off point if\nyou're looking to see where core is going, or where it could use a little love.\n\nThere are 3 sections; In Progress, TODO, and Done. These tasks are somewhat sorted by priority, but that shouldn't be\ntaken to mean that this is the order tasks will (or should) be completed in.\n\n## In Progress\n - [ ] [IN PROGRESS] Audio/Video\n     - [X] [DONE] encoding/streaming/decoding\n     - [X] [DONE] Call initiation\n     - [X] [DONE] Encryption\n     - [ ] [NEEDS TESTING] Video packet splitting.\n     - [ ] [IN PROGRESS] Auditing.\n     - [ ] [IN PROGRESS] Prevent audio skew (seems to be easily solvable client side.)\n     - [ ] [IN PROGRESS] Group chats, audio done.\n - [ ] Networking:\n     - [ ] [NEEDS TESTING] UPnP port forwarding. ([#969](https://github.com/irungentoo/toxcore/pull/969))\n     - [ ] [TODO] NAT-PMP port forwarding.\n - [ ] DHT:\n     - [ ] [ALMOST DONE] Metadata collection prevention. (docs/Prevent_Tracking.txt)\n     - [ ] [IN PROGRESS] Hardening against attacks.\n     - [ ] [IN PROGRESS] Optimizing the code.\n - [ ] [DONE] Friend only group chats\n     - [X] [DONE] Networking base.\n     - [X] [MOSTLY DONE] Syncing chat state between clients (nicknames, list of who is in chat, etc...)\n     - [ ] [TODO] Group private messages. (and adding friends from group chats using those private messages.)\n     - [ ] [TODO] Group file transfers.\n - [ ] [IN PROGRESS] Friends list syncing\n - [ ] [IN PROGRESS] Make toxcore thread safe.\n - [ ] [MOSTLY DONE] A way for people to connect to people on Tox if they are behind a bad NAT that blocks UDP (or is\njust unpunchable) ([docs/TCP_Network.txt](TCP_Network.txt)) (Current way doesn't scale very well.)\n\n## TODO\n - [ ] [TODO] Make the core save/datafile portable across client versions/different processor architectures.\n - [ ] [TODO] Friend_requests.c:\n     - [ ] [TODO] What happens when a friend request is received needs to be changed.\n     - [ ] [DONE?] Add multiple nospam functionality. ([#1317](https://github.com/irungentoo/toxcore/pull/1317))\n\n - [ ] [TODO] Offline messaging\n - [ ] [TODO] Security audit from professionals\n\n## Done\n - [X] [DONE] File transfers\n - [X] [DONE] IPV6 support\n - [X] [DONE] Encrypted Saves. (see: toxencryptsave)\n"
  },
  {
    "path": "docs/Tox_middle_level_network_protocol.txt",
    "content": "The TCP client and TCP server part are in a state that can be considered \nfeature complete. Why doesn't Tox support TCP yet even if those parts are \ncomplete?\n\nThe answer is that a way to ensure a smooth switchover between the TCP and UDP \nneeds to be added. If Tox first connects to the other user using TCP but then, \ndue to pure chance, manages to connect using the faster direct UDP connection, \nTox must switch seamlessly from the TCP to the UDP connection without there \nbeing any data loss or the other user going offline and then back online. The \ntransition must be seamless whatever both connected users are doing - be it \ntransferring files or simply chatting together.\n\nPossible evil/bad or simply TCP relays going offline must not impact the \nconnection between both clients.\n\nTypically, Tox will use more than one TCP relay to connect to other peers for \nmaximum connection stability, which means there must be a way for Tox to take \nadvantage of multiple relays in a way that the user will never be aware of, if one\nof them goes offline/tries to slow down the connection/decides to corrupt \npackets/etc.\n\nTo accomplish this, Tox needs something between the low level protocol (TCP) and \nhigh level Tox messaging protocol; hence the name middle level.\n\nThe plan is to move some functionality from lossless_UDP to a higher level: \nmore specifically, the functionality for detecting which packets a peer is \nmissing, and the ability to request and send them again. Lossless UDP uses plain \ntext packets to request missing packets from the other peer, while Tox is \ncurrently designed to kill the connection if any packet tampering is detected. \nThis works very well when connecting directly with someone because if the \nattacker can modify packets, it means he can kill your connection anyway. With \nTCP relays, however, that is not the case. As such the packets used to request \nmissing packets must be encrypted. If it is detected that a packet has been \ntampered, the connection must stay intact while the evil relay must be \ndisconnected from and replaced with a good relay; the behavior must be the same \nas if the relay had just suddenly gone offline. Of course, something to protect \nfrom evil \"friends\" framing relays must also be implemented.\n\nDetailed implementation details:\n\ncookie request packet:\n[uint8_t 24][Sender's DHT Public key (32 bytes)][Random nonce (24 \nbytes)][Encrypted message containing: [Sender's real public key (32 \nbytes)][padding (32 bytes)][uint64_t number (must be sent \nback untouched in cookie response)]]\nEncrypted message is encrypted with sender's DHT private key, receiver's DHT\npublic key and the nonce.\n\ncookie response packet:\n[uint8_t 25][Random nonce (24 bytes)][Encrypted message containing: \n[Cookie][uint64_t number (that was sent in the request)]]\nEncrypted message is encrypted with sender's DHT private key, receiver's DHT\npublic key and the nonce.\n\nThe Cookie should be basically:\n[nonce][encrypted data:[uint64_t time][Sender's real public key (32 \nbytes)][Sender's DHT public key (32 bytes)]]\n\nHandshake packet:\n[uint8_t 26][Cookie][nonce][Encrypted message containing: [random 24 bytes base \nnonce][session public key of the peer (32 bytes)][sha512 hash of the entire \nCookie sitting outside the encrypted part][Other Cookie (used by the other to \nrespond to the handshake packet)]]\n\nThe handshake packet is encrypted using the real private key of the sender, the \nreal public key of the receiver and the nonce.\n\n\nAlice wants to connect to Bob:\n\nAlice sends a cookie request packet to Bob and gets a cookie response back.\n\nAlice then generates a nonce and a temporary public/private keypair.\n\nAlice then takes that nonce and just generated private key, the obtained \ncookie, creates a new cookie and puts them in a handshake packet, which she \nsends to Bob.\n\nBob gets the handshake packet, accepts the connection request, then generates a \nnonce and a temporary public/private keypair and sends a handshake packet back \nwith this just generated information and with the cookie field being the Other \nCookie contained in the received handshake.\n\nBoth then use these temporary keys to generate the session key, with which every \ndata packet sent and received will be encrypted and decrypted. The nonce sent \nin the handshake will be used to encrypt the first data packet sent, the nonce \n+ 1 for the second, the nonce + 2 for the third, and so on.\n\nData packets:\n\n[uint8_t 27][uint16_t (in network byte order) the last 2 bytes of the nonce \nused to encrypt this][encrypted with the session key and a nonce:[plain data]]\n\nPlain data in the data packets:\n\n[uint32_t our recvbuffers buffer_start, (highest packet number handled + \n1)][uint32_t packet number if lossless, our sendbuffer buffer_end if \nlossy][data]\n\ndata ids:\n0: padding (skipped until we hit a non zero (data id) byte)\n1: packet request packet (lossy packet)\n2: connection kill packet (lossy packet) (tells the other that the connection is over)\n...\n16+: reserved for Messenger usage (lossless packets).\n192+: reserved for Messenger usage (lossy packets).\n255: reserved for Messenger usage (lossless packet)\n\npacket request packet: [uint8_t (1)][uint8_t num][uint8_t num][uint8_t \nnum]...[uint8_t num]\n\nThe list of nums are a list of packet numbers the other is requesting.\nIn order to get the real packet numbers from this list, take the recvbuffers buffer_start\nfrom the packet, subtract 1 from it and put it in packet_num, then start from the\nbeginning of the num list: if num is zero, add 255 to packet_num, then do the\nnext num. If num isn't zero, add its value to packet_num, note that the other\nhas requested we send this packet again to them, then continue to the next num in\nthe list.\n\n\n"
  },
  {
    "path": "docs/av_api.md",
    "content": "#A/V API reference\n\n##Take toxmsi/phone.c as a reference\n\n###Initialization:\n\n```\nphone_t* initPhone(uint16_t _listen_port, uint16_t _send_port);\n```\n\nfunction initializes sample phone. _listen_port and _send_port are variables only meant\nfor local testing. You will not have to do anything regarding to that since\neverything will be started within a mesenger.\n\n\nPhone requires one msi session and two rtp sessions ( one for audio and one for\nvideo ). \n\n```\nmsi_session_t* msi_init_session( void* _core_handler, const uint8_t* _user_agent );\n```\n\ninitializes msi session.\nParams:\n\n```\nvoid* _core_handler - pointer to an object handling networking,\nconst uint8_t* _user_agent - string describing phone client version.\n```\n\nReturn value:\nmsi_session_t* - pointer to a newly created msi session handler.\n\n###msi_session_t reference:\n\nHow to handle msi session:\nControlling is done via callbacks and action handlers.\nFirst register callbacks for every state/action received and make sure\nNOT TO PLACE SOMETHING LIKE LOOPS THAT TAKES A LOT OF TIME TO EXECUTE; every callback is being called \ndirectly from event loop. You can find examples in phone.c.\n\nRegister callbacks: \n```\nvoid msi_register_callback_call_started ( MCALLBACK );\nvoid msi_register_callback_call_canceled ( MCALLBACK );\nvoid msi_register_callback_call_rejected ( MCALLBACK );\nvoid msi_register_callback_call_ended ( MCALLBACK );\n\nvoid msi_register_callback_recv_invite ( MCALLBACK );\nvoid msi_register_callback_recv_ringing ( MCALLBACK );\nvoid msi_register_callback_recv_starting ( MCALLBACK );\nvoid msi_register_callback_recv_ending ( MCALLBACK );\nvoid msi_register_callback_recv_error ( MCALLBACK );\n\nvoid msi_register_callback_requ_timeout ( MCALLBACK );\n```\n\nMCALLBACK is defined as: void (*callback) (void* _arg)\nmsi_session_t* handler is being thrown as \\_arg so you can use that and \\_agent_handler to get to your own phone handler\ndirectly from callback.\n\n\nActions:\n\n```\nint msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms );\n```\n\nSends call invite. Before calling/sending invite msi_session_t::_friend_id is needed to be set or else\nit will not work. _call_type is type of the call ( Audio/Video ) and _timeoutms is how long \nwill poll wait until request is terminated.\n\n```\nint msi_hangup ( msi_session_t* _session );\n```\nHangs up active call\n\n```\nint msi_answer ( msi_session_t* _session, call_type _call_type );\n```\nAnswer incomming call. _call_type set's callee call type.\n\n```\nint msi_cancel ( msi_session_t* _session );\n```\nCancel current request.\n\n```\nint msi_reject ( msi_session_t* _session );\n```\nReject incomming call.\n\n\n###Now for rtp:\n\nYou will need 2 sessions; one for audio one for video.\nYou start them with:\n```\nrtp_session_t* rtp_init_session ( int _max_users, int _multi_session );\n```\n\nParams:\n```\nint _max_users - max users. -1 if undefined\nint _multi_session - any positive number means uses multi session; -1 if not.\n```\n\nReturn value:\n```\nrtp_session_t* - pointer to a newly created rtp session handler.\n```\n\n###How to handle rtp session:\nTake a look at\n```\nvoid* phone_handle_media_transport_poll ( void* _hmtc_args_p ) in phone.c\n```\non example. Basically what you do is just receive a message via:\n```\nstruct rtp_msg_s* rtp_recv_msg ( rtp_session_t* _session );\n```\n\nand then you use payload within the rtp_msg_s struct. Don't forget to deallocate it with:\nvoid rtp_free_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg );\nReceiving should be thread safe so don't worry about that.\n\nWhen you capture and encode a payload you want to send it ( obviously ).\n\nfirst create a new message with:\n```\nstruct rtp_msg_s* rtp_msg_new ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length );\n```\n\nand then send it with:\n```\nint rtp_send_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg, void* _core_handler );\n```\n\n_core_handler is the same network handler as in msi_session_s struct.\n\n\n##A/V initialization:\n```\nint init_receive_audio(codec_state *cs);\nint init_receive_video(codec_state *cs);\nInitialises the A/V decoders. On failure it will print the reason and return 0. On success it will return 1.\n\nint init_send_audio(codec_state *cs);\nint init_send_video(codec_state *cs);\nInitialises the A/V encoders. On failure it will print the reason and return 0. On success it will return 1.\ninit_send_audio will also let the user select an input device. init_send_video will determine the webcam's output codec and initialise the appropriate decoder.\n\nint video_encoder_refresh(codec_state *cs, int bps);\nReinitialises the video encoder with a new bitrate. ffmpeg does not expose the needed VP8 feature to change the bitrate on the fly, so this serves as a workaround.\nIn the future, VP8 should be used directly and ffmpeg should be dropped from the dependencies.\nThe variable bps is the required bitrate in bits per second.\n```\n\n\n###A/V encoding/decoding:\n```\nvoid *encode_video_thread(void *arg);\n```\nSpawns the video encoding thread. The argument should hold a pointer to a codec_state.\nThis function should only be called if video encoding is supported (when init_send_video returns 1).\nEach video frame gets encoded into a packet, which is sent via RTP. Every 60 frames a new bidirectional interframe is encoded.\n```\nvoid *encode_audio_thread(void *arg);\n```\nSpawns the audio encoding thread. The argument should hold a pointer to a codec_state.\nThis function should only be called if audio encoding is supported (when init_send_audio returns 1).\nAudio frames are read from the selected audio capture device during intitialisation. This audio capturing can be rerouted to a different device on the fly.\nEach audio frame is encoded into a packet, and sent via RTP. All audio frames have the same amount of samples, which is defined in AV_codec.h.\n```\nint video_decoder_refresh(codec_state *cs, int width, int height);\n```\nSets the SDL window dimensions and creates a pixel buffer with the requested size. It also creates a scaling context, which will be used to convert the input image format to YUV420P.\n\n```\nvoid *decode_video_thread(void *arg);\n```\nSpawns a video decoding thread. The argument should hold a pointer to a codec_state. The codec_state is assumed to contain a successfully initialised video decoder.\nThis function reads video packets and feeds them to the video decoder. If the video frame's resolution has changed, video_decoder_refresh() is called. Afterwards, the frame is displayed on the SDL window.\n```\nvoid *decode_audio_thread(void *arg);\n```\nSpawns an audio decoding thread. The argument should hold a pointer to a codec_state. The codec_state is assumed to contain a successfully initialised audio decoder.\nAll received audio packets are pushed into a jitter buffer and are reordered. If there is a missing packet, or a packet has arrived too late, it is treated as a lost packet and the audio decoder is informed of the packet loss. The audio decoder will then try to reconstruct the lost packet, based on information from previous packets.\nAudio is played on the default OpenAL output device.\n\n\nIf you have any more qustions/bug reports/feature request contact the following users on the irc channel #tox-dev on irc.freenode.net:\nFor RTP and MSI: mannol\nFor audio and video: Martijnvdc\n"
  },
  {
    "path": "docs/updates/Crypto.md",
    "content": "Encryption library used: http://nacl.cr.yp.to/\n\n\nWhen running the program for the first time the crypto_box_keypair() function is used to \ngenerate the users public-private key pair. (32 bytes each)\n\nThe generated public key is set as the client_id of the peer.\n\nAdding a friend\n---------------\n\nAlice adds Bob to her friend list by adding his 32 byte public key (client_id) to her friend list.  \n2 cases:  \ncase 1: Alice adds the public key of Bob, then Bob waits for Alice to attempt to connect to him.  \ncase 2: Bob and Alice add their respective public keys to their friend lists at the same time.  \n    \ncase 1:  \nAlice sends an onion data (see: Prevent_tracking.txt) packet to Bob with the encrypted part containing the friend request like so:  \n```\n[char with a value of 32][nospam number (4 bytes)][Message]\n```\n\nEx message: hello Bob it's me Alice -_- add me pl0x.\n\nFor more info on the nospam see: Spam_Prevention.txt\n        \nBob receives the request and decrypts the message using the function crypto_box_open()\n        \nIf the message decrypts successfully:   \nIf Alice is already in Bob's friend list: case 2  \nIf Alice is not in Bob's friend list and the nospam is good: Bob is prompt to add Alice and is shown the message from her.  \nIf Bob accepts Alice friend request he adds her public key to his friend list.  \n\ncase 2:  \nBob and Alice both have the others public key in their friend list, they are ready for the next step:   Connecting to an already added friend\n\nIn the next step only crypto_box() is used for encryption and only crypto_box_open() for decryption (just like in the last step.)\n\n\nConnecting to an already added friend\n-------------------------------------\n\nsee: Tox_middle_level_network_protocol.txt\n\nCrypto request packets\n--------------------------------------\n\n```\n[char with a value of 32][Bob (The reciever's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted message]\n```\n\nThe encrypted message is encrypted with crypto_box() (using Bob's public key, Alice's private key and the nonce (randomly generated 24 bytes)) and is a message from Alice in which she tells Bob who she is.\n\nEach node can route the request to the receiver if they are connected to him. This is to bypass bad NATs.\n"
  },
  {
    "path": "docs/updates/DHT.md",
    "content": "DHT protocol\n============\n\nNOTE: only the protocol section is up to date, the rest needs to be rewritten.\n\nFollows pretty much the principle of the torrent DHT: http://www.bittorrent.org/beps/bep_0005.html (READ IT)\n\nBut:\nVastly simplified packet format and encryption.\n\nBoostrapping:\nThe first time you install the client we bootstrap it with a node. (bandwidth should not be a problem as the client only needs to be sent one reply.)\n\n\nBasics\n------\n(All the numbers here are just guesses and are probably not optimal values)\n\nclient list: A list of node ids closest (mathematically see bittorrent doc) to ours matched with ip addresses + port number corresponding to that id and a timestamp containing the time or time since the client was successfully pinged.\n\n\"friends\" list: A list containing the node_ids of all our \"friends\" or clients we want to connect to.\nAlso contains the ip addresses + port + node_ids + timestamp(of last ping like in the client list) of the 8 clients closest (mathematically see bittorrent doc) to each \"friend\"\n\nOne pinged lists: \n-One for storing a list of ips along with their ping_ids and a timestamp for the ping requests\nEntries in the pinged lists expire after 5 seconds.\nIf one of the lists becomes full, the expire rate reduces itself one second or the new ping takes the place of the oldest one.\n\n\nEntries in client list and \"friends\" list expire after 300 seconds without ping response.\nEach client stores a maximum of 32 entries in its client list.\nEach client in the client list and \"friends\" list is pinged every 60 seconds.\nEach client in the client list and \"friends\" list has a timestamp which denote the last time it was successfully pinged.\nIf the corresponding clients timestamp is more than 130 seconds old it is considered bad.\nSend a get nodes request every 20 seconds to a random good node for each \"friend\" in our \"friends\" list.\nSend a get nodes request every 20 seconds to a random good node in the client list.\n\n\nWhen a client receives any request from another\n-----------------------------------------------\n- Respond to the request\n    - Ping request is replied to with with a ping response containing the same encrypted data\n    - 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\n\n- If the requesting client is not in the client list:\n    - If there are no bad clients in the list and the list is full:\n        - 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:\n            - Send a ping request to the client.\n        - if not forget about the client.\n\n    - If there are bad clients and/or the list isn't full:\n        - Send a ping request to the client \n\nWhen a client receives a response\n---------------------------------\n- Ping response\n    - If the node was previously pinged with a matching ping_id (check in the corresponding pinged list.)\n        - If the node is in the client list the matching client's timestamp is set to current time.\n        - If the node is in the \"friends\" list the matching client's timestamp is set to current time for every occurrence.\n        - If the node is not in the client list:\n            - If the list isn't full, add it to the list.\n            - If the list is full, the furthest away (mathematically see bittorrent doc) bad client is replaced by the new one.\n            - If the list is filled with good nodes replace the furthest client with it only if it is closer than the replaced node.\n        - for each friend in the \"friends\" list:\n            - If that friend's client list isn't full, add that client to it\n            - If that friend's client list contains bad clients, replace the furthest one with that client.\n            - If that friend's client list contains only good clients\n                - If the client is closer to the friend than one of the other clients, it replaces the farthest one\n                - If not, nothing happens.\n\n    - Send nodes\n        - If the ping_id matches what we sent previously (check in the corresponding pinged list.):\n            - Each node in the response is pinged.\n\n\n\n\n\nProtocol\n--------\n\nNode format: \n```\n[uint8_t family (2 == IPv4, 10 == IPv6, 130 == TCP IPv4, 138 == TCP IPv6)][ip (in network byte order), length=4 bytes if ipv4, 16 bytes if ipv6][port (in network byte order), length=2 bytes][char array (node_id), length=32 bytes]\n```\nsee also: DHT.h (pack_nodes() and unpack_nodes())\n\nValid queries and Responses:\n\nPing(Request and response): \n```\n[byte with value: 00 for request, 01 for response][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender: [1 byte type (0 for request, 1 for response)][random 8 byte (ping_id)]]\n```\nping_id = a random integer, the response must contain the exact same number as the request\n\n\nGet nodes (Request):\nPacket contents: \n```\n[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]]\n```\nValid replies: a send_nodes packet\n\nSend_nodes (response (for all addresses)): \n```\n[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]]\n```\n"
  },
  {
    "path": "docs/updates/Spam-Prevention.md",
    "content": " \nSituation 1:\nSomeone randomly goes around the DHT sending friend requests to everyone.\n\nPrevented by:\nEvery friend address: \n[client_id (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] \ncontains a number (nospam).\n\nThe nospam in every friend request to that friend must be that number.\n\nIf not it is rejected.\n"
  },
  {
    "path": "docs/updates/Symmetric-NAT-Transversal.md",
    "content": "Notes:\n\nFriend requests need to be routed.\n\nThe current DHT should be capable of punching all NATs except symmetric ones.\n\n######\n\nSymmetric NAT hole punching:\n\nIf we are not connected to the friend and if the DHT is queried and ips \nreturned for the friend are the same but the port is different, the friend is \nassumed to be behind a symmetric NAT.\n\nBefore attempting the procedure we first send a routed ping request to the \nfriend. This request is to be routed through the nodes who returned the ip of \nthe peer.\n\nAs soon as we receive one routed ping request from the other peer, we respond \nwith a ping response. \n\nPing request/response packet:\nSee: Crypto request packets in [[Crypto]]\n\nMessage:\nFor the ping request:\n[char with a value of 254][char with 0][8 byte random number]\n\nFor the ping response:\n[char with a value of 254][char with 1][8 byte random number (The same that was sent in the request)]\n\nAs soon as we get a proper ping response from the other we run the different \nports returned by the DHT through our port guessing algorithm.\n\n######\n\nPort guessing algorithm:\n\nRight now it just tries all the ports directly beside the known ports.(A better one is needed)\n\n######\n\nWe send DHT ping requests to all the guessed ports, only a couple at a time.\n"
  },
  {
    "path": "libtoxav.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libtoxav\nDescription: Tox A/V library\nRequires: libtoxcore\nVersion: @PACKAGE_VERSION@\nLibs: -L${libdir} -ltoxav @AV_LIBS@\nCflags: -I${includedir}\n"
  },
  {
    "path": "libtoxcore.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libtoxcore\nDescription: Tox protocol library\nRequires:\nVersion: @PACKAGE_VERSION@\nLibs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxencryptsave -ltoxcore @NACL_LIBS@ @LIBS@ @MATH_LDFLAGS@ @PTHREAD_LDFLAGS@\nCflags: -I${includedir}\n"
  },
  {
    "path": "m4/pkg.m4",
    "content": "# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-\n# serial 1 (pkg-config-0.24)\n# \n# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.\n#\n# This program is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n# General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, write to the Free Software\n# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n#\n# As a special exception to the GNU General Public License, if you\n# distribute this file as part of a program that contains a\n# configuration script generated by Autoconf, you may include it under\n# the same distribution terms that you use for the rest of that program.\n\n# PKG_PROG_PKG_CONFIG([MIN-VERSION])\n# ----------------------------------\nAC_DEFUN([PKG_PROG_PKG_CONFIG],\n[m4_pattern_forbid([^_?PKG_[A-Z_]+$])\nm4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])\nm4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])\nAC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])\nAC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])\nAC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])\n\nif test \"x$ac_cv_env_PKG_CONFIG_set\" != \"xset\"; then\n\tAC_PATH_TOOL([PKG_CONFIG], [pkg-config])\nfi\nif test -n \"$PKG_CONFIG\"; then\n\t_pkg_min_version=m4_default([$1], [0.9.0])\n\tAC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])\n\tif $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then\n\t\tAC_MSG_RESULT([yes])\n\telse\n\t\tAC_MSG_RESULT([no])\n\t\tPKG_CONFIG=\"\"\n\tfi\nfi[]dnl\n])# PKG_PROG_PKG_CONFIG\n\n# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])\n#\n# Check to see whether a particular set of modules exists.  Similar\n# to PKG_CHECK_MODULES(), but does not set variables or print errors.\n#\n# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])\n# only at the first occurrence in configure.ac, so if the first place\n# it's called might be skipped (such as if it is within an \"if\", you\n# have to call PKG_CHECK_EXISTS manually\n# --------------------------------------------------------------\nAC_DEFUN([PKG_CHECK_EXISTS],\n[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl\nif test -n \"$PKG_CONFIG\" && \\\n    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors \"$1\"]); then\n  m4_default([$2], [:])\nm4_ifvaln([$3], [else\n  $3])dnl\nfi])\n\n# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])\n# ---------------------------------------------\nm4_define([_PKG_CONFIG],\n[if test -n \"$$1\"; then\n    pkg_cv_[]$1=\"$$1\"\n elif test -n \"$PKG_CONFIG\"; then\n    PKG_CHECK_EXISTS([$3],\n                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 \"$3\" 2>/dev/null`\n\t\t      test \"x$?\" != \"x0\" && pkg_failed=yes ],\n\t\t     [pkg_failed=yes])\n else\n    pkg_failed=untried\nfi[]dnl\n])# _PKG_CONFIG\n\n# _PKG_SHORT_ERRORS_SUPPORTED\n# -----------------------------\nAC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],\n[AC_REQUIRE([PKG_PROG_PKG_CONFIG])\nif $PKG_CONFIG --atleast-pkgconfig-version 0.20; then\n        _pkg_short_errors_supported=yes\nelse\n        _pkg_short_errors_supported=no\nfi[]dnl\n])# _PKG_SHORT_ERRORS_SUPPORTED\n\n\n# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],\n# [ACTION-IF-NOT-FOUND])\n#\n#\n# Note that if there is a possibility the first call to\n# PKG_CHECK_MODULES might not happen, you should be sure to include an\n# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac\n#\n#\n# --------------------------------------------------------------\nAC_DEFUN([PKG_CHECK_MODULES],\n[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl\nAC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl\nAC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl\n\npkg_failed=no\nAC_MSG_CHECKING([for $1])\n\n_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])\n_PKG_CONFIG([$1][_LIBS], [libs], [$2])\n\nm4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS\nand $1[]_LIBS to avoid the need to call pkg-config.\nSee the pkg-config man page for more details.])\n\nif test $pkg_failed = yes; then\n   \tAC_MSG_RESULT([no])\n        _PKG_SHORT_ERRORS_SUPPORTED\n        if test $_pkg_short_errors_supported = yes; then\n\t        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs \"$2\" 2>&1`\n        else \n\t        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs \"$2\" 2>&1`\n        fi\n\t# Put the nasty error message in config.log where it belongs\n\techo \"$$1[]_PKG_ERRORS\" >&AS_MESSAGE_LOG_FD\n\n\tm4_default([$4], [AC_MSG_ERROR(\n[Package requirements ($2) were not met:\n\n$$1_PKG_ERRORS\n\nConsider adjusting the PKG_CONFIG_PATH environment variable if you\ninstalled software in a non-standard prefix.\n\n_PKG_TEXT])[]dnl\n        ])\nelif test $pkg_failed = untried; then\n     \tAC_MSG_RESULT([no])\n\tm4_default([$4], [AC_MSG_FAILURE(\n[The pkg-config script could not be found or is too old.  Make sure it\nis in your PATH or set the PKG_CONFIG environment variable to the full\npath to pkg-config.\n\n_PKG_TEXT\n\nTo get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl\n        ])\nelse\n\t$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS\n\t$1[]_LIBS=$pkg_cv_[]$1[]_LIBS\n        AC_MSG_RESULT([yes])\n\t$3\nfi[]dnl\n])# PKG_CHECK_MODULES\n\n\n# PKG_INSTALLDIR(DIRECTORY)\n# -------------------------\n# Substitutes the variable pkgconfigdir as the location where a module\n# should install pkg-config .pc files. By default the directory is\n# $libdir/pkgconfig, but the default can be changed by passing\n# DIRECTORY. The user can override through the --with-pkgconfigdir\n# parameter.\nAC_DEFUN([PKG_INSTALLDIR],\n[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])\nm4_pushdef([pkg_description],\n    [pkg-config installation directory @<:@]pkg_default[@:>@])\nAC_ARG_WITH([pkgconfigdir],\n    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,\n    [with_pkgconfigdir=]pkg_default)\nAC_SUBST([pkgconfigdir], [$with_pkgconfigdir])\nm4_popdef([pkg_default])\nm4_popdef([pkg_description])\n]) dnl PKG_INSTALLDIR\n\n\n# PKG_NOARCH_INSTALLDIR(DIRECTORY)\n# -------------------------\n# Substitutes the variable noarch_pkgconfigdir as the location where a\n# module should install arch-independent pkg-config .pc files. By\n# default the directory is $datadir/pkgconfig, but the default can be\n# changed by passing DIRECTORY. The user can override through the\n# --with-noarch-pkgconfigdir parameter.\nAC_DEFUN([PKG_NOARCH_INSTALLDIR],\n[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])\nm4_pushdef([pkg_description],\n    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])\nAC_ARG_WITH([noarch-pkgconfigdir],\n    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,\n    [with_noarch_pkgconfigdir=]pkg_default)\nAC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])\nm4_popdef([pkg_default])\nm4_popdef([pkg_description])\n]) dnl PKG_NOARCH_INSTALLDIR\n"
  },
  {
    "path": "other/DHT_bootstrap.c",
    "content": "\n/* DHT boostrap\n *\n * A simple DHT boostrap node for tox.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/DHT.h\"\n#include \"../toxcore/LAN_discovery.h\"\n#include \"../toxcore/friend_requests.h\"\n#include \"../toxcore/util.h\"\n\n#define TCP_RELAY_ENABLED\n\n#ifdef TCP_RELAY_ENABLED\n#include \"../toxcore/TCP_server.h\"\n#endif\n\n#include \"../testing/misc_tools.c\"\n\n#ifdef DHT_NODE_EXTRA_PACKETS\n#include \"./bootstrap_node_packets.h\"\n\n#define DHT_VERSION_NUMBER 1\n#define DHT_MOTD \"This is a test motd\"\n#endif\n\n/* Sleep function (x = milliseconds) */\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#include <arpa/inet.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\n#define PORT 33445\n\n\nvoid manage_keys(DHT *dht)\n{\n    const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;\n    uint8_t keys[KEYS_SIZE];\n\n    FILE *keys_file = fopen(\"key\", \"r\");\n\n    if (keys_file != NULL) {\n        /* If file was opened successfully -- load keys,\n           otherwise save new keys */\n        size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);\n\n        if (read_size != KEYS_SIZE) {\n            printf(\"Error while reading the key file\\nExiting.\\n\");\n            exit(1);\n        }\n\n        memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);\n        memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);\n        printf(\"Keys loaded successfully.\\n\");\n    } else {\n        memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n        memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);\n        keys_file = fopen(\"key\", \"w\");\n\n        if (keys_file == NULL) {\n            printf(\"Error opening key file in write mode.\\nKeys will not be saved.\\n\");\n            return;\n        }\n\n        if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file) != KEYS_SIZE) {\n            printf(\"Error while writing the key file.\\nExiting.\\n\");\n            exit(1);\n        }\n\n        printf(\"Keys saved successfully.\\n\");\n    }\n\n    fclose(keys_file);\n}\n\nint main(int argc, char *argv[])\n{\n    if (argc == 2 && !strncasecmp(argv[1], \"-h\", 3)) {\n        printf(\"Usage (connected)  : %s [--ipv4|--ipv6] IP PORT KEY\\n\", argv[0]);\n        printf(\"Usage (unconnected): %s [--ipv4|--ipv6]\\n\", argv[0]);\n        exit(0);\n    }\n\n    /* let user override default by cmdline */\n    uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    /* Initialize networking -\n       Bind to ip 0.0.0.0 / [::] : PORT */\n    IP ip;\n    ip_init(&ip, ipv6enabled);\n\n    DHT *dht = new_DHT(new_networking(ip, PORT));\n    Onion *onion = new_onion(dht);\n    Onion_Announce *onion_a = new_onion_announce(dht);\n\n#ifdef DHT_NODE_EXTRA_PACKETS\n    bootstrap_set_callbacks(dht->net, DHT_VERSION_NUMBER, DHT_MOTD, sizeof(DHT_MOTD));\n#endif\n\n    if (!(onion && onion_a)) {\n        printf(\"Something failed to initialize.\\n\");\n        exit(1);\n    }\n\n    perror(\"Initialization\");\n\n    manage_keys(dht);\n    printf(\"Public key: \");\n    uint32_t i;\n\n#ifdef TCP_RELAY_ENABLED\n#define NUM_PORTS 3\n    uint16_t ports[NUM_PORTS] = {443, 3389, PORT};\n    TCP_Server *tcp_s = new_TCP_server(ipv6enabled, NUM_PORTS, ports, dht->self_secret_key, onion);\n\n    if (tcp_s == NULL) {\n        printf(\"TCP server failed to initialize.\\n\");\n        exit(1);\n    }\n\n#endif\n\n    FILE *file;\n    file = fopen(\"PUBLIC_ID.txt\", \"w\");\n\n    for (i = 0; i < 32; i++) {\n        printf(\"%02hhX\", dht->self_public_key[i]);\n        fprintf(file, \"%02hhX\", dht->self_public_key[i]);\n    }\n\n    fclose(file);\n\n    printf(\"\\n\");\n    printf(\"Port: %u\\n\", ntohs(dht->net->port));\n\n    if (argc > argvoffset + 3) {\n        printf(\"Trying to bootstrap into the network...\\n\");\n        uint16_t port = htons(atoi(argv[argvoffset + 2]));\n        uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]);\n        int res = DHT_bootstrap_from_address(dht, argv[argvoffset + 1],\n                                             ipv6enabled, port, bootstrap_key);\n        free(bootstrap_key);\n\n        if (!res) {\n            printf(\"Failed to convert \\\"%s\\\" into an IP address. Exiting...\\n\", argv[argvoffset + 1]);\n            exit(1);\n        }\n    }\n\n    int is_waiting_for_dht_connection = 1;\n\n    uint64_t last_LANdiscovery = 0;\n    LANdiscovery_init(dht);\n\n    while (1) {\n        if (is_waiting_for_dht_connection && DHT_isconnected(dht)) {\n            printf(\"Connected to other bootstrap node successfully.\\n\");\n            is_waiting_for_dht_connection = 0;\n        }\n\n        do_DHT(dht);\n\n        if (is_timeout(last_LANdiscovery, is_waiting_for_dht_connection ? 5 : LAN_DISCOVERY_INTERVAL)) {\n            send_LANdiscovery(htons(PORT), dht);\n            last_LANdiscovery = unix_time();\n        }\n\n#ifdef TCP_RELAY_ENABLED\n        do_TCP_server(tcp_s);\n#endif\n        networking_poll(dht->net);\n\n        c_sleep(1);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "other/DHTnodes",
    "content": "As maintaining 2 separate lists of the same information seemed redundant, this list has been phased out.\n\nFor a current DHT node list please visit https://wiki.tox.chat/doku.php?id=users:nodes\n"
  },
  {
    "path": "other/Makefile.inc",
    "content": "bin_PROGRAMS += DHT_bootstrap\n\nDHT_bootstrap_SOURCES = ../other/DHT_bootstrap.c \\\n                        ../toxcore/DHT.h \\\n                        ../toxcore/friend_requests.h \\\n                        ../other/bootstrap_node_packets.h \\\n                        ../other/bootstrap_node_packets.c\n\nDHT_bootstrap_CFLAGS = -I$(top_srcdir)/other \\\n                        $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\nDHT_bootstrap_LDADD =   $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\nEXTRA_DIST +=           $(top_srcdir)/other/DHTnodes \\\n                        $(top_srcdir)/other/tox.png\n"
  },
  {
    "path": "other/apidsl/README.md",
    "content": "This folder contains the input file (``tox.in.h``) that has to be used to generate the ``tox.h`` api with: https://github.com/iphydf/apidsl\n\n# Minimal requirements\n\nThere are some minimal requirements to contribute to ``tox.h``:\n* unix environment\n* ``astyle`` ``>=2.03``\n* [``apidsl``](https://github.com/iphydf/apidsl) (you can use provided service with curl instead)\n\n## Quick way\n\nIf you want to do it quickly and you don't have time for anything other than copypasting commands, you should have ``curl`` installed.\n\n\n1. Make sure that you have ``curl`` and ``>=astyle-2.03`` installed\n2. Modify [``tox.in.h``](/other/apidsl/tox.in.h)\n3. Run command below ↓\n\nCommand to run from ``toxcore`` directory (quick way, involves using curl):\n```bash\nrm toxcore/tox.h && \\\n( curl -X POST --data-binary @- https://criticism.herokuapp.com/apidsl < ./other/apidsl/tox.in.h > ./toxcore/tox.h ) && \\\nastyle --options=./other/astyle/astylerc ./toxcore/tox.h\n```\n\nWhen formatting will be complete, you should see output like:\n```\nFormatted  ./toxcore/tox.h\n```\n\nYou may want to make sure with ``git diff`` that changes made in ``tox.h`` reflect changes in ``tox.in.h``.\n\nAnd you're done.\n\n\n## Manually\n\nIf you prefer to have more control over what is happening, there are steps below:\n\n1. Install [``apidsl``](https://github.com/iphydf/apidsl)\n2. Install ``astyle``, version 2.03 or later.\n3. Modify [``tox.in.h``](/other/apidsl/tox.in.h)\n4. Use ``apidsl`` ``??``\n5. Parse generated ``tox.h`` with astyle, minimal command for it would be:\n```bash\nastyle --options=./other/astyle/astylerc ./toxcore/tox.h\n```\n\n**Always pass output from ``apidsl`` through astyle.**"
  },
  {
    "path": "other/apidsl/tox.in.h",
    "content": "%{\n/* tox.h\n *\n * The Tox public API.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TOX_H\n#define TOX_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n%}\n\n\n/*****************************************************************************\n * `tox.h` SHOULD *NOT* BE EDITED MANUALLY – any changes should be made to   *\n * `tox.in.h`, located in `other/apidsl/`. For instructions on how to        *\n * generate `tox.h` from `tox.in.h` please refer to `other/apidsl/README.md` *\n *****************************************************************************/\n\n\n/** \\page core Public core API for Tox clients.\n *\n * Every function that can fail takes a function-specific error code pointer\n * that can be used to diagnose problems with the Tox state or the function\n * arguments. The error code pointer can be NULL, which does not influence the\n * function's behaviour, but can be done if the reason for failure is irrelevant\n * to the client.\n *\n * The exception to this rule are simple allocation functions whose only failure\n * mode is allocation failure. They return NULL in that case, and do not set an\n * error code.\n *\n * Every error code type has an OK value to which functions will set their error\n * code value on success. Clients can keep their error code uninitialised before\n * passing it to a function. The library guarantees that after returning, the\n * value pointed to by the error code pointer has been initialised.\n *\n * Functions with pointer parameters often have a NULL error code, meaning they\n * could not perform any operation, because one of the required parameters was\n * NULL. Some functions operate correctly or are defined as effectless on NULL.\n *\n * Some functions additionally return a value outside their\n * return type domain, or a bool containing true on success and false on\n * failure.\n *\n * All functions that take a Tox instance pointer will cause undefined behaviour\n * when passed a NULL Tox pointer.\n *\n * All integer values are expected in host byte order.\n *\n * Functions with parameters with enum types cause unspecified behaviour if the\n * enumeration value is outside the valid range of the type. If possible, the\n * function will try to use a sane default, but there will be no error code,\n * and one possible action for the function to take is to have no effect.\n */\n\n/** \\subsection events Events and callbacks\n *\n * Events are handled by callbacks. One callback can be registered per event.\n * All events have a callback function type named `tox_{event}_cb` and a\n * function to register it named `tox_callback_{event}`. Passing a NULL\n * callback will result in no callback being registered for that event. Only\n * one callback per event can be registered, so if a client needs multiple\n * event listeners, it needs to implement the dispatch functionality itself.\n */\n\n/** \\subsection threading Threading implications\n *\n * It is possible to run multiple concurrent threads with a Tox instance for\n * each thread. It is also possible to run all Tox instances in the same thread.\n * A common way to run Tox (multiple or single instance) is to have one thread\n * running a simple ${tox.iterate} loop, sleeping for ${tox.iteration_interval}\n * milliseconds on each iteration.\n *\n * If you want to access a single Tox instance from multiple threads, access\n * to the instance must be synchronised. While multiple threads can concurrently\n * access multiple different Tox instances, no more than one API function can\n * operate on a single instance at any given time.\n *\n * Functions that write to variable length byte arrays will always have a size\n * function associated with them. The result of this size function is only valid\n * until another mutating function (one that takes a pointer to non-const Tox)\n * is called. Thus, clients must ensure that no other thread calls a mutating\n * function between the call to the size function and the call to the retrieval\n * function.\n *\n * E.g. to get the current nickname, one would write\n *\n * \\code\n * size_t length = ${tox.self.name.size}(tox);\n * uint8_t *name = malloc(length);\n * if (!name) abort();\n * ${tox.self.name.get}(tox, name);\n * \\endcode\n *\n * If any other thread calls ${tox.self.name.set} while this thread is allocating\n * memory, the length may have become invalid, and the call to\n * ${tox.self.name.get} may cause undefined behaviour.\n */\n\n// The rest of this file is in class tox.\nclass tox {\n\n/**\n * The Tox instance type. All the state associated with a connection is held\n * within the instance. Multiple instances can exist and operate concurrently.\n * The maximum number of Tox instances that can exist on a single network\n * device is limited. Note that this is not just a per-process limit, since the\n * limiting factor is the number of usable ports on a device.\n */\nstruct this;\n\n\n/*******************************************************************************\n *\n * :: API version\n *\n ******************************************************************************/\n\n\n/**\n * The major version number. Incremented when the API or ABI changes in an\n * incompatible way.\n */\n#define TOX_VERSION_MAJOR               0u\n/**\n * The minor version number. Incremented when functionality is added without\n * breaking the API or ABI. Set to 0 when the major version number is\n * incremented.\n */\n#define TOX_VERSION_MINOR               0u\n/**\n * The patch or revision number. Incremented when bugfixes are applied without\n * changing any functionality or API or ABI.\n */\n#define TOX_VERSION_PATCH               0u\n\n/**\n * A macro to check at preprocessing time whether the client code is compatible\n * with the installed version of Tox.\n */\n#define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH)      \\\n  (TOX_VERSION_MAJOR == MAJOR &&                                \\\n   (TOX_VERSION_MINOR > MINOR ||                                \\\n    (TOX_VERSION_MINOR == MINOR &&                              \\\n     TOX_VERSION_PATCH >= PATCH)))\n\n/**\n * A macro to make compilation fail if the client code is not compatible with\n * the installed version of Tox.\n */\n#define TOX_VERSION_REQUIRE(MAJOR, MINOR, PATCH)                \\\n  typedef char tox_required_version[TOX_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1]\n\nstatic namespace version {\n\n  /**\n   * Return the major version number of the library. Can be used to display the\n   * Tox library version or to check whether the client is compatible with the\n   * dynamically linked version of Tox.\n   */\n  uint32_t major();\n\n  /**\n   * Return the minor version number of the library.\n   */\n  uint32_t minor();\n\n  /**\n   * Return the patch number of the library.\n   */\n  uint32_t patch();\n\n  /**\n   * Return whether the compiled library version is compatible with the passed\n   * version numbers.\n   */\n  bool is_compatible(uint32_t major, uint32_t minor, uint32_t patch);\n\n}\n\n/**\n * A convenience macro to call tox_version_is_compatible with the currently\n * compiling API version.\n */\n#define TOX_VERSION_IS_ABI_COMPATIBLE()                         \\\n  tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH)\n\n/*******************************************************************************\n *\n * :: Numeric constants\n *\n ******************************************************************************/\n\n\n/**\n * The size of a Tox Public Key in bytes.\n */\nconst PUBLIC_KEY_SIZE              = 32;\n\n/**\n * The size of a Tox Secret Key in bytes.\n */\nconst SECRET_KEY_SIZE              = 32;\n\n/**\n * The size of a Tox address in bytes. Tox addresses are in the format\n * [Public Key ($PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)].\n *\n * The checksum is computed over the Public Key and the nospam value. The first\n * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an\n * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam.\n */\nconst ADDRESS_SIZE                = PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t);\n\n/**\n * Maximum length of a nickname in bytes.\n */\nconst MAX_NAME_LENGTH             = 128;\n\n/**\n * Maximum length of a status message in bytes.\n */\nconst MAX_STATUS_MESSAGE_LENGTH   = 1007;\n\n/**\n * Maximum length of a friend request message in bytes.\n */\nconst MAX_FRIEND_REQUEST_LENGTH   = 1016;\n\n/**\n * Maximum length of a single message after which it should be split.\n */\nconst MAX_MESSAGE_LENGTH          = 1372;\n\n/**\n * Maximum size of custom packets. TODO: should be LENGTH?\n */\nconst MAX_CUSTOM_PACKET_SIZE      = 1373;\n\n/**\n * The number of bytes in a hash generated by $hash.\n */\nconst HASH_LENGTH                 = 32;\n\n/**\n * The number of bytes in a file id.\n */\nconst FILE_ID_LENGTH              = 32;\n\n/**\n * Maximum file name length for file transfers.\n */\nconst MAX_FILENAME_LENGTH         = 255;\n\n\n/*******************************************************************************\n *\n * :: Global enumerations\n *\n ******************************************************************************/\n\n\n/**\n * Represents the possible statuses a client can have.\n */\nenum class USER_STATUS {\n  /**\n   * User is online and available.\n   */\n  NONE,\n  /**\n   * User is away. Clients can set this e.g. after a user defined\n   * inactivity time.\n   */\n  AWAY,\n  /**\n   * User is busy. Signals to other clients that this client does not\n   * currently wish to communicate.\n   */\n  BUSY,\n}\n\n\n/**\n * Represents message types for ${tox.friend.send.message} and group chat\n * messages.\n */\nenum class MESSAGE_TYPE {\n  /**\n   * Normal text message. Similar to PRIVMSG on IRC.\n   */\n  NORMAL,\n  /**\n   * A message describing an user action. This is similar to /me (CTCP ACTION)\n   * on IRC.\n   */\n  ACTION,\n}\n\n\n/*******************************************************************************\n *\n * :: Startup options\n *\n ******************************************************************************/\n\n\n/**\n * Type of proxy used to connect to TCP relays.\n */\nenum class PROXY_TYPE {\n  /**\n   * Don't use a proxy.\n   */\n  NONE,\n  /**\n   * HTTP proxy using CONNECT.\n   */\n  HTTP,\n  /**\n   * SOCKS proxy for simple socket pipes.\n   */\n  SOCKS5,\n}\n\n/**\n * Type of savedata to create the Tox instance from.\n */\nenum class SAVEDATA_TYPE {\n  /**\n   * No savedata.\n   */\n  NONE,\n  /**\n   * Savedata is one that was obtained from ${savedata.get}\n   */\n  TOX_SAVE,\n  /**\n   * Savedata is a secret key of length ${SECRET_KEY_SIZE}\n   */\n  SECRET_KEY,\n}\n\n\nstatic class options {\n  /**\n   * This struct contains all the startup options for Tox. You can either allocate\n   * this object yourself, and pass it to $default, or call\n   * $new to get a new default options object.\n   */\n  struct this {\n    /**\n     * The type of socket to create.\n     *\n     * If this is set to false, an IPv4 socket is created, which subsequently\n     * only allows IPv4 communication.\n     * If it is set to true, an IPv6 socket is created, allowing both IPv4 and\n     * IPv6 communication.\n     */\n    bool ipv6_enabled;\n\n    /**\n     * Enable the use of UDP communication when available.\n     *\n     * Setting this to false will force Tox to use TCP only. Communications will\n     * need to be relayed through a TCP relay node, potentially slowing them down.\n     * Disabling UDP support is necessary when using anonymous proxies or Tor.\n     */\n    bool udp_enabled;\n\n    namespace proxy {\n      /**\n       * Pass communications through a proxy.\n       */\n      PROXY_TYPE type;\n\n      /**\n       * The IP address or DNS name of the proxy to be used.\n       *\n       * If used, this must be non-NULL and be a valid DNS name. The name must not\n       * exceed 255 characters, and be in a NUL-terminated C string format\n       * (255 chars + 1 NUL byte).\n       *\n       * This member is ignored (it can be NULL) if proxy_type is TOX_PROXY_TYPE_NONE.\n       */\n      string host;\n\n      /**\n       * The port to use to connect to the proxy server.\n       *\n       * Ports must be in the range (1, 65535). The value is ignored if\n       * proxy_type is TOX_PROXY_TYPE_NONE.\n       */\n      uint16_t port;\n    }\n\n    /**\n     * The start port of the inclusive port range to attempt to use.\n     *\n     * If both start_port and end_port are 0, the default port range will be\n     * used: [33445, 33545].\n     *\n     * If either start_port or end_port is 0 while the other is non-zero, the\n     * non-zero port will be the only port in the range.\n     *\n     * Having start_port > end_port will yield the same behavior as if start_port\n     * and end_port were swapped.\n     */\n    uint16_t start_port;\n\n    /**\n     * The end port of the inclusive port range to attempt to use.\n     */\n    uint16_t end_port;\n\n    /**\n     * The port to use for the TCP server (relay). If 0, the TCP server is\n     * disabled.\n     *\n     * Enabling it is not required for Tox to function properly.\n     *\n     * When enabled, your Tox instance can act as a TCP relay for other Tox\n     * instance. This leads to increased traffic, thus when writing a client\n     * it is recommended to enable TCP server only if the user has an option\n     * to disable it.\n     */\n    uint16_t tcp_port;\n\n    namespace savedata {\n      /**\n       * The type of savedata to load from.\n       */\n      SAVEDATA_TYPE type;\n\n      /**\n       * The savedata.\n       */\n      const uint8_t[length] data;\n\n      /**\n       * The length of the savedata.\n       */\n      size_t length;\n    }\n  }\n\n\n  /**\n   * Initialises a $this object with the default options.\n   *\n   * The result of this function is independent of the original options. All\n   * values will be overwritten, no values will be read (so it is permissible\n   * to pass an uninitialised object).\n   *\n   * If options is NULL, this function has no effect.\n   *\n   * @param options An options object to be filled with default options.\n   */\n  void default();\n\n\n  /**\n   * Allocates a new $this object and initialises it with the default\n   * options. This function can be used to preserve long term ABI compatibility by\n   * giving the responsibility of allocation and deallocation to the Tox library.\n   *\n   * Objects returned from this function must be freed using the $free\n   * function.\n   *\n   * @return A new $this object with default options or NULL on failure.\n   */\n  static this new() {\n    /**\n     * The function failed to allocate enough memory for the options struct.\n     */\n    MALLOC,\n  }\n\n\n  /**\n   * Releases all resources associated with an options objects.\n   *\n   * Passing a pointer that was not returned by $new results in\n   * undefined behaviour.\n   */\n  void free();\n}\n\n\n/*******************************************************************************\n *\n * :: Creation and destruction\n *\n ******************************************************************************/\n\n\n/**\n * @brief Creates and initialises a new Tox instance with the options passed.\n *\n * This function will bring the instance into a valid state. Running the event\n * loop with a new instance will operate correctly.\n *\n * If loading failed or succeeded only partially, the new or partially loaded\n * instance is returned and an error code is set.\n *\n * @param options An options object as described above. If this parameter is\n *   NULL, the default options are used.\n *\n * @see $iterate for the event loop.\n *\n * @return A new Tox instance pointer on success or NULL on failure.\n */\nstatic this new(const options_t *options) {\n  NULL,\n  /**\n   * The function was unable to allocate enough memory to store the internal\n   * structures for the Tox object.\n   */\n  MALLOC,\n  /**\n   * The function was unable to bind to a port. This may mean that all ports\n   * have already been bound, e.g. by other Tox instances, or it may mean\n   * a permission error. You may be able to gather more information from errno.\n   */\n  PORT_ALLOC,\n\n  namespace PROXY {\n    /**\n     * proxy_type was invalid.\n     */\n    BAD_TYPE,\n    /**\n     * proxy_type was valid but the proxy_host passed had an invalid format\n     * or was NULL.\n     */\n    BAD_HOST,\n    /**\n     * proxy_type was valid, but the proxy_port was invalid.\n     */\n    BAD_PORT,\n    /**\n     * The proxy address passed could not be resolved.\n     */\n    NOT_FOUND,\n  }\n\n  namespace LOAD {\n    /**\n     * The byte array to be loaded contained an encrypted save.\n     */\n    ENCRYPTED,\n    /**\n     * The data format was invalid. This can happen when loading data that was\n     * saved by an older version of Tox, or when the data has been corrupted.\n     * When loading from badly formatted data, some data may have been loaded,\n     * and the rest is discarded. Passing an invalid length parameter also\n     * causes this error.\n     */\n    BAD_FORMAT,\n  }\n}\n\n\n/**\n * Releases all resources associated with the Tox instance and disconnects from\n * the network.\n *\n * After calling this function, the Tox pointer becomes invalid. No other\n * functions can be called, and the pointer value can no longer be read.\n */\nvoid kill();\n\n\nuint8_t[size] savedata {\n  /**\n   * Calculates the number of bytes required to store the tox instance with\n   * $get. This function cannot fail. The result is always greater than 0.\n   *\n   * @see threading for concurrency implications.\n   */\n  size();\n\n  /**\n   * Store all information associated with the tox instance to a byte array.\n   *\n   * @param data A memory region large enough to store the tox instance data.\n   *   Call $size to find the number of bytes required. If this parameter\n   *   is NULL, this function has no effect.\n   */\n  get();\n}\n\n\n/*******************************************************************************\n *\n * :: Connection lifecycle and event loop\n *\n ******************************************************************************/\n\n\n/**\n * Sends a \"get nodes\" request to the given bootstrap node with IP, port, and\n * public key to setup connections.\n *\n * This function will attempt to connect to the node using UDP. You must use\n * this function even if ${options.this.udp_enabled} was set to false.\n *\n * @param address The hostname or IP address (IPv4 or IPv6) of the node.\n * @param port The port on the host on which the bootstrap Tox instance is\n *   listening.\n * @param public_key The long term public key of the bootstrap node\n *   ($PUBLIC_KEY_SIZE bytes).\n * @return true on success.\n */\nbool bootstrap(string address, uint16_t port, const uint8_t[PUBLIC_KEY_SIZE] public_key) {\n  NULL,\n  /**\n   * The address could not be resolved to an IP address, or the IP address\n   * passed was invalid.\n   */\n  BAD_HOST,\n  /**\n   * The port passed was invalid. The valid port range is (1, 65535).\n   */\n  BAD_PORT,\n}\n\n\n/**\n * Adds additional host:port pair as TCP relay.\n *\n * This function can be used to initiate TCP connections to different ports on\n * the same bootstrap node, or to add TCP relays without using them as\n * bootstrap nodes.\n *\n * @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay.\n * @param port The port on the host on which the TCP relay is listening.\n * @param public_key The long term public key of the TCP relay\n *   ($PUBLIC_KEY_SIZE bytes).\n * @return true on success.\n */\nbool add_tcp_relay(string address, uint16_t port, const uint8_t[PUBLIC_KEY_SIZE] public_key)\n    with error for bootstrap;\n\n\n/**\n * Protocols that can be used to connect to the network or friends.\n */\nenum class CONNECTION {\n  /**\n   * There is no connection. This instance, or the friend the state change is\n   * about, is now offline.\n   */\n  NONE,\n  /**\n   * A TCP connection has been established. For the own instance, this means it\n   * is connected through a TCP relay, only. For a friend, this means that the\n   * connection to that particular friend goes through a TCP relay.\n   */\n  TCP,\n  /**\n   * A UDP connection has been established. For the own instance, this means it\n   * is able to send UDP packets to DHT nodes, but may still be connected to\n   * a TCP relay. For a friend, this means that the connection to that\n   * particular friend was built using direct UDP packets.\n   */\n  UDP,\n}\n\n\ninline namespace self {\n\n  CONNECTION connection_status {\n    /**\n     * Return whether we are connected to the DHT. The return value is equal to the\n     * last value received through the `${event connection_status}` callback.\n     */\n    get();\n  }\n\n\n  /**\n   * This event is triggered whenever there is a change in the DHT connection\n   * state. When disconnected, a client may choose to call $bootstrap again, to\n   * reconnect to the DHT. Note that this state may frequently change for short\n   * amounts of time. Clients should therefore not immediately bootstrap on\n   * receiving a disconnect.\n   *\n   * TODO: how long should a client wait before bootstrapping again?\n   */\n  event connection_status {\n    /**\n     * @param connection_status Whether we are connected to the DHT.\n     */\n    typedef void(CONNECTION connection_status);\n  }\n\n}\n\n\n/**\n * Return the time in milliseconds before $iterate() should be called again\n * for optimal performance.\n */\nconst uint32_t iteration_interval();\n\n\n/**\n * The main loop that needs to be run in intervals of $iteration_interval()\n * milliseconds.\n */\nvoid iterate();\n\n\n/*******************************************************************************\n *\n * :: Internal client information (Tox address/id)\n *\n ******************************************************************************/\n\n\ninline namespace self {\n\n  uint8_t[ADDRESS_SIZE] address {\n    /**\n     * Writes the Tox friend address of the client to a byte array. The address is\n     * not in human-readable format. If a client wants to display the address,\n     * formatting is required.\n     *\n     * @param address A memory region of at least $ADDRESS_SIZE bytes. If this\n     *   parameter is NULL, this function has no effect.\n     * @see $ADDRESS_SIZE for the address format.\n     */\n    get();\n  }\n\n\n  uint32_t nospam {\n    /**\n     * Set the 4-byte nospam part of the address.\n     *\n     * @param nospam Any 32 bit unsigned integer.\n     */\n    set();\n\n    /**\n     * Get the 4-byte nospam part of the address.\n     */\n    get();\n  }\n\n\n  uint8_t[PUBLIC_KEY_SIZE] public_key {\n    /**\n     * Copy the Tox Public Key (long term) from the Tox object.\n     *\n     * @param public_key A memory region of at least $PUBLIC_KEY_SIZE bytes. If\n     *   this parameter is NULL, this function has no effect.\n     */\n    get();\n  }\n\n\n  uint8_t[SECRET_KEY_SIZE] secret_key {\n    /**\n     * Copy the Tox Secret Key from the Tox object.\n     *\n     * @param secret_key A memory region of at least $SECRET_KEY_SIZE bytes. If\n     *   this parameter is NULL, this function has no effect.\n     */\n    get();\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: User-visible client information (nickname/status)\n *\n ******************************************************************************/\n\n\n/**\n * Common error codes for all functions that set a piece of user-visible\n * client information.\n */\nerror for set_info {\n  NULL,\n  /**\n   * Information length exceeded maximum permissible size.\n   */\n  TOO_LONG,\n}\n\n\ninline namespace self {\n\n  uint8_t[length <= MAX_NAME_LENGTH] name {\n    /**\n     * Set the nickname for the Tox client.\n     *\n     * Nickname length cannot exceed $MAX_NAME_LENGTH. If length is 0, the name\n     * parameter is ignored (it can be NULL), and the nickname is set back to empty.\n     *\n     * @param name A byte array containing the new nickname.\n     * @param length The size of the name byte array.\n     *\n     * @return true on success.\n     */\n    set() with error for set_info;\n\n    /**\n     * Return the length of the current nickname as passed to $set.\n     *\n     * If no nickname was set before calling this function, the name is empty,\n     * and this function returns 0.\n     *\n     * @see threading for concurrency implications.\n     */\n    size();\n\n    /**\n     * Write the nickname set by $set to a byte array.\n     *\n     * If no nickname was set before calling this function, the name is empty,\n     * and this function has no effect.\n     *\n     * Call $size to find out how much memory to allocate for\n     * the result.\n     *\n     * @param name A valid memory location large enough to hold the nickname.\n     *   If this parameter is NULL, the function has no effect.\n     */\n    get();\n\n  }\n\n\n  uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] status_message {\n    /**\n     * Set the client's status message.\n     *\n     * Status message length cannot exceed $MAX_STATUS_MESSAGE_LENGTH. If\n     * length is 0, the status parameter is ignored (it can be NULL), and the\n     * user status is set back to empty.\n     */\n    set() with error for set_info;\n\n    /**\n     * Return the length of the current status message as passed to $set.\n     *\n     * If no status message was set before calling this function, the status\n     * is empty, and this function returns 0.\n     *\n     * @see threading for concurrency implications.\n     */\n    size();\n\n    /**\n     * Write the status message set by $set to a byte array.\n     *\n     * If no status message was set before calling this function, the status is\n     * empty, and this function has no effect.\n     *\n     * Call $size to find out how much memory to allocate for\n     * the result.\n     *\n     * @param status A valid memory location large enough to hold the status message.\n     *   If this parameter is NULL, the function has no effect.\n     */\n    get();\n  }\n\n\n  USER_STATUS status {\n    /**\n     * Set the client's user status.\n     *\n     * @param user_status One of the user statuses listed in the enumeration above.\n     */\n    set();\n\n    /**\n     * Returns the client's user status.\n     */\n    get();\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: Friend list management\n *\n ******************************************************************************/\n\n\nnamespace friend {\n\n  /**\n   * Add a friend to the friend list and send a friend request.\n   *\n   * A friend request message must be at least 1 byte long and at most\n   * $MAX_FRIEND_REQUEST_LENGTH.\n   *\n   * Friend numbers are unique identifiers used in all functions that operate on\n   * friends. Once added, a friend number is stable for the lifetime of the Tox\n   * object. After saving the state and reloading it, the friend numbers may not\n   * be the same as before. Deleting a friend creates a gap in the friend number\n   * set, which is filled by the next adding of a friend. Any pattern in friend\n   * numbers should not be relied on.\n   *\n   * If more than INT32_MAX friends are added, this function causes undefined\n   * behaviour.\n   *\n   * @param address The address of the friend (returned by ${self.address.get} of\n   *   the friend you wish to add) it must be $ADDRESS_SIZE bytes.\n   * @param message The message that will be sent along with the friend request.\n   * @param length The length of the data byte array.\n   *\n   * @return the friend number on success, UINT32_MAX on failure.\n   */\n  uint32_t add(\n      const uint8_t[ADDRESS_SIZE] address,\n      const uint8_t[length <= MAX_FRIEND_REQUEST_LENGTH] message\n  ) {\n    NULL,\n    /**\n     * The length of the friend request message exceeded\n     * $MAX_FRIEND_REQUEST_LENGTH.\n     */\n    TOO_LONG,\n    /**\n     * The friend request message was empty. This, and the TOO_LONG code will\n     * never be returned from $add_norequest.\n     */\n    NO_MESSAGE,\n    /**\n     * The friend address belongs to the sending client.\n     */\n    OWN_KEY,\n    /**\n     * A friend request has already been sent, or the address belongs to a friend\n     * that is already on the friend list.\n     */\n    ALREADY_SENT,\n    /**\n     * The friend address checksum failed.\n     */\n    BAD_CHECKSUM,\n    /**\n     * The friend was already there, but the nospam value was different.\n     */\n    SET_NEW_NOSPAM,\n    /**\n     * A memory allocation failed when trying to increase the friend list size.\n     */\n    MALLOC,\n  }\n\n\n  /**\n   * Add a friend without sending a friend request.\n   *\n   * This function is used to add a friend in response to a friend request. If the\n   * client receives a friend request, it can be reasonably sure that the other\n   * client added this client as a friend, eliminating the need for a friend\n   * request.\n   *\n   * This function is also useful in a situation where both instances are\n   * controlled by the same entity, so that this entity can perform the mutual\n   * friend adding. In this case, there is no need for a friend request, either.\n   *\n   * @param public_key A byte array of length $PUBLIC_KEY_SIZE containing the\n   *   Public Key (not the Address) of the friend to add.\n   *\n   * @return the friend number on success, UINT32_MAX on failure.\n   * @see $add for a more detailed description of friend numbers.\n   */\n  uint32_t add_norequest(const uint8_t[PUBLIC_KEY_SIZE] public_key)\n      with error for add;\n\n\n  /**\n   * Remove a friend from the friend list.\n   *\n   * This does not notify the friend of their deletion. After calling this\n   * function, this client will appear offline to the friend and no communication\n   * can occur between the two.\n   *\n   * @param friend_number Friend number for the friend to be deleted.\n   *\n   * @return true on success.\n   */\n  bool delete(uint32_t friend_number) {\n    /**\n     * There was no friend with the given friend number. No friends were deleted.\n     */\n    FRIEND_NOT_FOUND,\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: Friend list queries\n *\n ******************************************************************************/\n\nnamespace friend {\n\n  /**\n   * Return the friend number associated with that Public Key.\n   *\n   * @return the friend number on success, UINT32_MAX on failure.\n   * @param public_key A byte array containing the Public Key.\n   */\n  const uint32_t by_public_key(const uint8_t[PUBLIC_KEY_SIZE] public_key) {\n    NULL,\n    /**\n     * No friend with the given Public Key exists on the friend list.\n     */\n    NOT_FOUND,\n  }\n\n\n  /**\n   * Checks if a friend with the given friend number exists and returns true if\n   * it does.\n   */\n  const bool exists(uint32_t friend_number);\n\n\n}\n\ninline namespace self {\n\n  uint32_t[size] friend_list {\n    /**\n     * Return the number of friends on the friend list.\n     *\n     * This function can be used to determine how much memory to allocate for\n     * $get.\n     */\n    size();\n\n\n    /**\n     * Copy a list of valid friend numbers into an array.\n     *\n     * Call $size to determine the number of elements to allocate.\n     *\n     * @param list A memory region with enough space to hold the friend list. If\n     *   this parameter is NULL, this function has no effect.\n     */\n    get();\n  }\n\n}\n\n\n\nnamespace friend {\n\n  uint8_t[PUBLIC_KEY_SIZE] public_key {\n    /**\n     * Copies the Public Key associated with a given friend number to a byte array.\n     *\n     * @param friend_number The friend number you want the Public Key of.\n     * @param public_key A memory region of at least $PUBLIC_KEY_SIZE bytes. If\n     *   this parameter is NULL, this function has no effect.\n     *\n     * @return true on success.\n     */\n    get(uint32_t friend_number) {\n      /**\n       * No friend with the given number exists on the friend list.\n       */\n      FRIEND_NOT_FOUND,\n    }\n  }\n\n}\n\nnamespace friend {\n\n  uint64_t last_online {\n    /**\n    * Return a unix-time timestamp of the last time the friend associated with a given\n    * friend number was seen online. This function will return UINT64_MAX on error.\n    *\n    * @param friend_number The friend number you want to query.\n    */\n    get(uint32_t friend_number) {\n      /**\n       * No friend with the given number exists on the friend list.\n       */\n      FRIEND_NOT_FOUND,\n    }\n  }\n\n}\n\n/*******************************************************************************\n *\n * :: Friend-specific state queries (can also be received through callbacks)\n *\n ******************************************************************************/\n\n\nnamespace friend {\n\n  /**\n   * Common error codes for friend state query functions.\n   */\n  error for query {\n    /**\n     * The pointer parameter for storing the query result (name, message) was\n     * NULL. Unlike the `_self_` variants of these functions, which have no effect\n     * when a parameter is NULL, these functions return an error in that case.\n     */\n    NULL,\n    /**\n     * The friend_number did not designate a valid friend.\n     */\n    FRIEND_NOT_FOUND,\n  }\n\n\n  uint8_t[length <= MAX_NAME_LENGTH] name {\n    /**\n     * Return the length of the friend's name. If the friend number is invalid, the\n     * return value is unspecified.\n     *\n     * The return value is equal to the `length` argument received by the last\n     * `${event name}` callback.\n     */\n    size(uint32_t friend_number)\n        with error for query;\n\n    /**\n     * Write the name of the friend designated by the given friend number to a byte\n     * array.\n     *\n     * Call $size to determine the allocation size for the `name`\n     * parameter.\n     *\n     * The data written to `name` is equal to the data received by the last\n     * `${event name}` callback.\n     *\n     * @param name A valid memory region large enough to store the friend's name.\n     *\n     * @return true on success.\n     */\n    get(uint32_t friend_number)\n        with error for query;\n  }\n\n\n  /**\n   * This event is triggered when a friend changes their name.\n   */\n  event name {\n    /**\n     * @param friend_number The friend number of the friend whose name changed.\n     * @param name A byte array containing the same data as\n     *   ${name.get} would write to its `name` parameter.\n     * @param length A value equal to the return value of\n     *   ${name.size}.\n     */\n    typedef void(uint32_t friend_number, const uint8_t[length <= MAX_NAME_LENGTH] name);\n  }\n\n\n  uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] status_message {\n    /**\n     * Return the length of the friend's status message. If the friend number is\n     * invalid, the return value is SIZE_MAX.\n     */\n    size(uint32_t friend_number)\n        with error for query;\n\n    /**\n     * Write the status message of the friend designated by the given friend number to a byte\n     * array.\n     *\n     * Call $size to determine the allocation size for the `status_name`\n     * parameter.\n     *\n     * The data written to `status_message` is equal to the data received by the last\n     * `${event status_message}` callback.\n     *\n     * @param status_message A valid memory region large enough to store the friend's status message.\n     */\n    get(uint32_t friend_number)\n        with error for query;\n\n  }\n\n\n  /**\n   * This event is triggered when a friend changes their status message.\n   */\n  event status_message {\n    /**\n     * @param friend_number The friend number of the friend whose status message\n     *   changed.\n     * @param message A byte array containing the same data as\n     *   ${status_message.get} would write to its `status_message` parameter.\n     * @param length A value equal to the return value of\n     *   ${status_message.size}.\n     */\n    typedef void(uint32_t friend_number, const uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] message);\n  }\n\n\n  USER_STATUS status {\n    /**\n     * Return the friend's user status (away/busy/...). If the friend number is\n     * invalid, the return value is unspecified.\n     *\n     * The status returned is equal to the last status received through the\n     * `${event status}` callback.\n     */\n    get(uint32_t friend_number)\n        with error for query;\n  }\n\n\n  /**\n   * This event is triggered when a friend changes their user status.\n   */\n  event status {\n    /**\n     * @param friend_number The friend number of the friend whose user status\n     *   changed.\n     * @param status The new user status.\n     */\n    typedef void(uint32_t friend_number, USER_STATUS status);\n  }\n\n\n  CONNECTION connection_status {\n    /**\n     * Check whether a friend is currently connected to this client.\n     *\n     * The result of this function is equal to the last value received by the\n     * `${event connection_status}` callback.\n     *\n     * @param friend_number The friend number for which to query the connection\n     *   status.\n     *\n     * @return the friend's connection status as it was received through the\n     *   `${event connection_status}` event.\n     */\n    get(uint32_t friend_number)\n        with error for query;\n  }\n\n\n  /**\n   * This event is triggered when a friend goes offline after having been online,\n   * or when a friend goes online.\n   *\n   * This callback is not called when adding friends. It is assumed that when\n   * adding friends, their connection status is initially offline.\n   */\n  event connection_status {\n    /**\n     * @param friend_number The friend number of the friend whose connection status\n     *   changed.\n     * @param connection_status The result of calling\n     *   ${connection_status.get} on the passed friend_number.\n     */\n    typedef void(uint32_t friend_number, CONNECTION connection_status);\n  }\n\n\n  bool typing {\n    /**\n     * Check whether a friend is currently typing a message.\n     *\n     * @param friend_number The friend number for which to query the typing status.\n     *\n     * @return true if the friend is typing.\n     * @return false if the friend is not typing, or the friend number was\n     *   invalid. Inspect the error code to determine which case it is.\n     */\n    get(uint32_t friend_number)\n        with error for query;\n  }\n\n\n  /**\n   * This event is triggered when a friend starts or stops typing.\n   */\n  event typing {\n    /**\n     * @param friend_number The friend number of the friend who started or stopped\n     *   typing.\n     * @param is_typing The result of calling ${typing.get} on the passed\n     *   friend_number.\n     */\n    typedef void(uint32_t friend_number, bool is_typing);\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: Sending private messages\n *\n ******************************************************************************/\n\n\ninline namespace self {\n\n  bool typing {\n    /**\n     * Set the client's typing status for a friend.\n     *\n     * The client is responsible for turning it on or off.\n     *\n     * @param friend_number The friend to which the client is typing a message.\n     * @param typing The typing status. True means the client is typing.\n     *\n     * @return true on success.\n     */\n    set(uint32_t friend_number) {\n      /**\n       * The friend number did not designate a valid friend.\n       */\n      FRIEND_NOT_FOUND,\n    }\n  }\n\n}\n\n\nnamespace friend {\n\n  namespace send {\n\n    /**\n     * Send a text chat message to an online friend.\n     *\n     * This function creates a chat message packet and pushes it into the send\n     * queue.\n     *\n     * The message length may not exceed $MAX_MESSAGE_LENGTH. Larger messages\n     * must be split by the client and sent as separate messages. Other clients can\n     * then reassemble the fragments. Messages may not be empty.\n     *\n     * The return value of this function is the message ID. If a read receipt is\n     * received, the triggered `${event read_receipt}` event will be passed this message ID.\n     *\n     * Message IDs are unique per friend. The first message ID is 0. Message IDs are\n     * incremented by 1 each time a message is sent. If UINT32_MAX messages were\n     * sent, the next message ID is 0.\n     *\n     * @param type Message type (normal, action, ...).\n     * @param friend_number The friend number of the friend to send the message to.\n     * @param message A non-NULL pointer to the first element of a byte array\n     *   containing the message text.\n     * @param length Length of the message to be sent.\n     */\n    uint32_t message(uint32_t friend_number, MESSAGE_TYPE type, const uint8_t[length <= MAX_MESSAGE_LENGTH] message) {\n      NULL,\n      /**\n       * The friend number did not designate a valid friend.\n       */\n      FRIEND_NOT_FOUND,\n      /**\n       * This client is currently not connected to the friend.\n       */\n      FRIEND_NOT_CONNECTED,\n      /**\n       * An allocation error occurred while increasing the send queue size.\n       */\n      SENDQ,\n      /**\n       * Message length exceeded $MAX_MESSAGE_LENGTH.\n       */\n      TOO_LONG,\n      /**\n       * Attempted to send a zero-length message.\n       */\n      EMPTY,\n    }\n\n  }\n\n\n  /**\n   * This event is triggered when the friend receives the message sent with\n   * ${send.message} with the corresponding message ID.\n   */\n  event read_receipt {\n    /**\n     * @param friend_number The friend number of the friend who received the message.\n     * @param message_id The message ID as returned from ${send.message}\n     *   corresponding to the message sent.\n     */\n    typedef void(uint32_t friend_number, uint32_t message_id);\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: Receiving private messages and friend requests\n *\n ******************************************************************************/\n\n\nnamespace friend {\n\n  /**\n   * This event is triggered when a friend request is received.\n   */\n  event request {\n    /**\n     * @param public_key The Public Key of the user who sent the friend request.\n     * @param time_delta A delta in seconds between when the message was composed\n     *   and when it is being transmitted. For messages that are sent immediately,\n     *   it will be 0. If a message was written and couldn't be sent immediately\n     *   (due to a connection failure, for example), the time_delta is an\n     *   approximation of when it was composed.\n     * @param message The message they sent along with the request.\n     * @param length The size of the message byte array.\n     */\n    typedef void(const uint8_t[PUBLIC_KEY_SIZE] public_key\n        //, uint32_t time_delta\n        , const uint8_t[length <= MAX_MESSAGE_LENGTH] message);\n  }\n\n\n  /**\n   * This event is triggered when a message from a friend is received.\n   */\n  event message {\n    /**\n     * @param friend_number The friend number of the friend who sent the message.\n     * @param time_delta Time between composition and sending.\n     * @param message The message data they sent.\n     * @param length The size of the message byte array.\n     *\n     * @see ${event request} for more information on time_delta.\n     */\n    typedef void(uint32_t friend_number\n        //, uint32_t time_delta\n        , MESSAGE_TYPE type, const uint8_t[length <= MAX_MESSAGE_LENGTH] message);\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: File transmission: common between sending and receiving\n *\n ******************************************************************************/\n\n\n/**\n * Generates a cryptographic hash of the given data.\n *\n * This function may be used by clients for any purpose, but is provided\n * primarily for validating cached avatars. This use is highly recommended to\n * avoid unnecessary avatar updates.\n *\n * If hash is NULL or data is NULL while length is not 0 the function returns false,\n * otherwise it returns true.\n *\n * This function is a wrapper to internal message-digest functions.\n *\n * @param hash A valid memory location the hash data. It must be at least\n *   TOX_HASH_LENGTH bytes in size.\n * @param data Data to be hashed or NULL.\n * @param length Size of the data array or 0.\n *\n * @return true if hash was not NULL.\n */\nstatic bool hash(uint8_t[HASH_LENGTH] hash, const uint8_t[length] data);\n\n\nnamespace file {\n\n  enum KIND {\n    /**\n     * Arbitrary file data. Clients can choose to handle it based on the file name\n     * or magic or any other way they choose.\n     */\n    DATA,\n    /**\n     * Avatar file_id. This consists of $hash(image).\n     * Avatar data. This consists of the image data.\n     *\n     * Avatars can be sent at any time the client wishes. Generally, a client will\n     * send the avatar to a friend when that friend comes online, and to all\n     * friends when the avatar changed. A client can save some traffic by\n     * remembering which friend received the updated avatar already and only send\n     * it if the friend has an out of date avatar.\n     *\n     * Clients who receive avatar send requests can reject it (by sending\n     * ${CONTROL.CANCEL} before any other controls), or accept it (by\n     * sending ${CONTROL.RESUME}). The file_id of length $HASH_LENGTH bytes\n     * (same length as $FILE_ID_LENGTH) will contain the hash. A client can compare\n     * this hash with a saved hash and send ${CONTROL.CANCEL} to terminate the avatar\n     * transfer if it matches.\n     *\n     * When file_size is set to 0 in the transfer request it means that the client\n     * has no avatar.\n     */\n    AVATAR,\n  }\n\n\n  enum class CONTROL {\n    /**\n     * Sent by the receiving side to accept a file send request. Also sent after a\n     * $PAUSE command to continue sending or receiving.\n     */\n    RESUME,\n    /**\n     * Sent by clients to pause the file transfer. The initial state of a file\n     * transfer is always paused on the receiving side and running on the sending\n     * side. If both the sending and receiving side pause the transfer, then both\n     * need to send $RESUME for the transfer to resume.\n     */\n    PAUSE,\n    /**\n     * Sent by the receiving side to reject a file send request before any other\n     * commands are sent. Also sent by either side to terminate a file transfer.\n     */\n    CANCEL,\n  }\n\n\n  /**\n   * Sends a file control command to a friend for a given file transfer.\n   *\n   * @param friend_number The friend number of the friend the file is being\n   *   transferred to or received from.\n   * @param file_number The friend-specific identifier for the file transfer.\n   * @param control The control command to send.\n   *\n   * @return true on success.\n   */\n  bool control(uint32_t friend_number, uint32_t file_number, CONTROL control) {\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    FRIEND_NOT_FOUND,\n    /**\n     * This client is currently not connected to the friend.\n     */\n    FRIEND_NOT_CONNECTED,\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    NOT_FOUND,\n    /**\n     * A RESUME control was sent, but the file transfer is running normally.\n     */\n    NOT_PAUSED,\n    /**\n     * A RESUME control was sent, but the file transfer was paused by the other\n     * party. Only the party that paused the transfer can resume it.\n     */\n    DENIED,\n    /**\n     * A PAUSE control was sent, but the file transfer was already paused.\n     */\n    ALREADY_PAUSED,\n    /**\n     * Packet queue is full.\n     */\n    SENDQ,\n  }\n\n\n  /**\n   * This event is triggered when a file control command is received from a\n   * friend.\n   */\n  event recv_control {\n    /**\n     * When receiving ${CONTROL.CANCEL}, the client should release the\n     * resources associated with the file number and consider the transfer failed.\n     *\n     * @param friend_number The friend number of the friend who is sending the file.\n     * @param file_number The friend-specific file number the data received is\n     *   associated with.\n     * @param control The file control command received.\n     */\n    typedef void(uint32_t friend_number, uint32_t file_number, CONTROL control);\n  }\n\n  /**\n   * Sends a file seek control command to a friend for a given file transfer.\n   *\n   * This function can only be called to resume a file transfer right before\n   * ${CONTROL.RESUME} is sent.\n   *\n   * @param friend_number The friend number of the friend the file is being\n   *   received from.\n   * @param file_number The friend-specific identifier for the file transfer.\n   * @param position The position that the file should be seeked to.\n   */\n  bool seek(uint32_t friend_number, uint32_t file_number, uint64_t position) {\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    FRIEND_NOT_FOUND,\n    /**\n     * This client is currently not connected to the friend.\n     */\n    FRIEND_NOT_CONNECTED,\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    NOT_FOUND,\n    /**\n     * File was not in a state where it could be seeked.\n     */\n    DENIED,\n    /**\n     * Seek position was invalid\n     */\n    INVALID_POSITION,\n    /**\n     * Packet queue is full.\n     */\n    SENDQ,\n  }\n\n\n  error for get {\n    NULL,\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    FRIEND_NOT_FOUND,\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    NOT_FOUND,\n  }\n\n  /**\n   * Copy the file id associated to the file transfer to a byte array.\n   *\n   * @param friend_number The friend number of the friend the file is being\n   *   transferred to or received from.\n   * @param file_number The friend-specific identifier for the file transfer.\n   * @param file_id A memory region of at least $FILE_ID_LENGTH bytes. If\n   *   this parameter is NULL, this function has no effect.\n   *\n   * @return true on success.\n   */\n  const bool get_file_id(uint32_t friend_number, uint32_t file_number, uint8_t[FILE_ID_LENGTH] file_id)\n      with error for get;\n\n}\n\n\n/*******************************************************************************\n *\n * :: File transmission: sending\n *\n ******************************************************************************/\n\n\nnamespace file {\n\n  /**\n   * Send a file transmission request.\n   *\n   * Maximum filename length is $MAX_FILENAME_LENGTH bytes. The filename\n   * should generally just be a file name, not a path with directory names.\n   *\n   * If a non-UINT64_MAX file size is provided, it can be used by both sides to\n   * determine the sending progress. File size can be set to UINT64_MAX for streaming\n   * data of unknown size.\n   *\n   * File transmission occurs in chunks, which are requested through the\n   * `${event chunk_request}` event.\n   *\n   * When a friend goes offline, all file transfers associated with the friend are\n   * purged from core.\n   *\n   * If the file contents change during a transfer, the behaviour is unspecified\n   * in general. What will actually happen depends on the mode in which the file\n   * was modified and how the client determines the file size.\n   *\n   * - If the file size was increased\n   *   - and sending mode was streaming (file_size = UINT64_MAX), the behaviour\n   *     will be as expected.\n   *   - and sending mode was file (file_size != UINT64_MAX), the\n   *     ${event chunk_request} callback will receive length = 0 when Core thinks\n   *     the file transfer has finished. If the client remembers the file size as\n   *     it was when sending the request, it will terminate the transfer normally.\n   *     If the client re-reads the size, it will think the friend cancelled the\n   *     transfer.\n   * - If the file size was decreased\n   *   - and sending mode was streaming, the behaviour is as expected.\n   *   - and sending mode was file, the callback will return 0 at the new\n   *     (earlier) end-of-file, signalling to the friend that the transfer was\n   *     cancelled.\n   * - If the file contents were modified\n   *   - at a position before the current read, the two files (local and remote)\n   *     will differ after the transfer terminates.\n   *   - at a position after the current read, the file transfer will succeed as\n   *     expected.\n   *   - In either case, both sides will regard the transfer as complete and\n   *     successful.\n   *\n   * @param friend_number The friend number of the friend the file send request\n   *   should be sent to.\n   * @param kind The meaning of the file to be sent.\n   * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if\n   *   unknown or streaming.\n   * @param file_id A file identifier of length $FILE_ID_LENGTH that can be used to\n   *   uniquely identify file transfers across core restarts. If NULL, a random one will\n   *   be generated by core. It can then be obtained by using $get_file_id().\n   * @param filename Name of the file. Does not need to be the actual name. This\n   *   name will be sent along with the file send request.\n   * @param filename_length Size in bytes of the filename.\n   *\n   * @return A file number used as an identifier in subsequent callbacks. This\n   *   number is per friend. File numbers are reused after a transfer terminates.\n   *   On failure, this function returns UINT32_MAX. Any pattern in file numbers\n   *   should not be relied on.\n   */\n  uint32_t send(uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t[FILE_ID_LENGTH] file_id, const uint8_t[filename_length <= MAX_FILENAME_LENGTH] filename) {\n    NULL,\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    FRIEND_NOT_FOUND,\n    /**\n     * This client is currently not connected to the friend.\n     */\n    FRIEND_NOT_CONNECTED,\n    /**\n     * Filename length exceeded $MAX_FILENAME_LENGTH bytes.\n     */\n    NAME_TOO_LONG,\n    /**\n     * Too many ongoing transfers. The maximum number of concurrent file transfers\n     * is 256 per friend per direction (sending and receiving).\n     */\n    TOO_MANY,\n  }\n\n\n  /**\n   * Send a chunk of file data to a friend.\n   *\n   * This function is called in response to the `${event chunk_request}` callback. The\n   * length parameter should be equal to the one received though the callback.\n   * If it is zero, the transfer is assumed complete. For files with known size,\n   * Core will know that the transfer is complete after the last byte has been\n   * received, so it is not necessary (though not harmful) to send a zero-length\n   * chunk to terminate. For streams, core will know that the transfer is finished\n   * if a chunk with length less than the length requested in the callback is sent.\n   *\n   * @param friend_number The friend number of the receiving friend for this file.\n   * @param file_number The file transfer identifier returned by tox_file_send.\n   * @param position The file or stream position from which to continue reading.\n   * @return true on success.\n   */\n  bool send_chunk(uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t[length] data) {\n    /**\n     * The length parameter was non-zero, but data was NULL.\n     */\n    NULL,\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    FRIEND_NOT_FOUND,\n    /**\n     * This client is currently not connected to the friend.\n     */\n    FRIEND_NOT_CONNECTED,\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    NOT_FOUND,\n    /**\n     * File transfer was found but isn't in a transferring state: (paused, done,\n     * broken, etc...) (happens only when not called from the request chunk callback).\n     */\n    NOT_TRANSFERRING,\n    /**\n     * Attempted to send more or less data than requested. The requested data size is\n     * adjusted according to maximum transmission unit and the expected end of\n     * the file. Trying to send less or more than requested will return this error.\n     */\n    INVALID_LENGTH,\n    /**\n     * Packet queue is full.\n     */\n    SENDQ,\n    /**\n     * Position parameter was wrong.\n     */\n    WRONG_POSITION,\n  }\n\n\n  /**\n   * This event is triggered when Core is ready to send more file data.\n   */\n  event chunk_request {\n    /**\n     * If the length parameter is 0, the file transfer is finished, and the client's\n     * resources associated with the file number should be released. After a call\n     * with zero length, the file number can be reused for future file transfers.\n     *\n     * If the requested position is not equal to the client's idea of the current\n     * file or stream position, it will need to seek. In case of read-once streams,\n     * the client should keep the last read chunk so that a seek back can be\n     * supported. A seek-back only ever needs to read from the last requested chunk.\n     * This happens when a chunk was requested, but the send failed. A seek-back\n     * request can occur an arbitrary number of times for any given chunk.\n     *\n     * In response to receiving this callback, the client should call the function\n     * `$send_chunk` with the requested chunk. If the number of bytes sent\n     * through that function is zero, the file transfer is assumed complete. A\n     * client must send the full length of data requested with this callback.\n     *\n     * @param friend_number The friend number of the receiving friend for this file.\n     * @param file_number The file transfer identifier returned by $send.\n     * @param position The file or stream position from which to continue reading.\n     * @param length The number of bytes requested for the current chunk.\n     */\n    typedef void(uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length);\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: File transmission: receiving\n *\n ******************************************************************************/\n\n\nnamespace file {\n\n  /**\n   * This event is triggered when a file transfer request is received.\n   */\n  event recv {\n    /**\n     * The client should acquire resources to be associated with the file transfer.\n     * Incoming file transfers start in the PAUSED state. After this callback\n     * returns, a transfer can be rejected by sending a ${CONTROL.CANCEL}\n     * control command before any other control commands. It can be accepted by\n     * sending ${CONTROL.RESUME}.\n     *\n     * @param friend_number The friend number of the friend who is sending the file\n     *   transfer request.\n     * @param file_number The friend-specific file number the data received is\n     *   associated with.\n     * @param kind The meaning of the file to be sent.\n     * @param file_size Size in bytes of the file the client wants to send,\n     *   UINT64_MAX if unknown or streaming.\n     * @param filename Name of the file. Does not need to be the actual name. This\n     *   name will be sent along with the file send request.\n     * @param filename_length Size in bytes of the filename.\n     */\n    typedef void(uint32_t friend_number, uint32_t file_number, uint32_t kind,\n        uint64_t file_size, const uint8_t[filename_length <= MAX_FILENAME_LENGTH] filename);\n  }\n\n\n  /**\n   * This event is first triggered when a file transfer request is received, and\n   * subsequently when a chunk of file data for an accepted request was received.\n   */\n  event recv_chunk {\n    /**\n     * When length is 0, the transfer is finished and the client should release the\n     * resources it acquired for the transfer. After a call with length = 0, the\n     * file number can be reused for new file transfers.\n     *\n     * If position is equal to file_size (received in the file_receive callback)\n     * when the transfer finishes, the file was received completely. Otherwise, if\n     * file_size was UINT64_MAX, streaming ended successfully when length is 0.\n     *\n     * @param friend_number The friend number of the friend who is sending the file.\n     * @param file_number The friend-specific file number the data received is\n     *   associated with.\n     * @param position The file position of the first byte in data.\n     * @param data A byte array containing the received chunk.\n     * @param length The length of the received chunk.\n     */\n    typedef void(uint32_t friend_number, uint32_t file_number, uint64_t position,\n        const uint8_t[length] data);\n  }\n\n}\n\n\n/*******************************************************************************\n *\n * :: Group chat management\n *\n ******************************************************************************/\n\n\n/******************************************************************************\n *\n * :: Group chat message sending and receiving\n *\n ******************************************************************************/\n\n\n/*******************************************************************************\n *\n * :: Low-level custom packet sending and receiving\n *\n ******************************************************************************/\n\n\nnamespace friend {\n\n  inline namespace send {\n\n    error for custom_packet {\n      NULL,\n      /**\n       * The friend number did not designate a valid friend.\n       */\n      FRIEND_NOT_FOUND,\n      /**\n       * This client is currently not connected to the friend.\n       */\n      FRIEND_NOT_CONNECTED,\n      /**\n       * The first byte of data was not in the specified range for the packet type.\n       * This range is 200-254 for lossy, and 160-191 for lossless packets.\n       */\n      INVALID,\n      /**\n       * Attempted to send an empty packet.\n       */\n      EMPTY,\n      /**\n       * Packet data length exceeded $MAX_CUSTOM_PACKET_SIZE.\n       */\n      TOO_LONG,\n      /**\n       * Packet queue is full.\n       */\n      SENDQ,\n    }\n\n    /**\n     * Send a custom lossy packet to a friend.\n     *\n     * The first byte of data must be in the range 200-254. Maximum length of a\n     * custom packet is $MAX_CUSTOM_PACKET_SIZE.\n     *\n     * Lossy packets behave like UDP packets, meaning they might never reach the\n     * other side or might arrive more than once (if someone is messing with the\n     * connection) or might arrive in the wrong order.\n     *\n     * Unless latency is an issue, it is recommended that you use lossless custom\n     * packets instead.\n     *\n     * @param friend_number The friend number of the friend this lossy packet\n     *   should be sent to.\n     * @param data A byte array containing the packet data.\n     * @param length The length of the packet data byte array.\n     *\n     * @return true on success.\n     */\n    bool lossy_packet(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data)\n        with error for custom_packet;\n\n\n    /**\n     * Send a custom lossless packet to a friend.\n     *\n     * The first byte of data must be in the range 160-191. Maximum length of a\n     * custom packet is $MAX_CUSTOM_PACKET_SIZE.\n     *\n     * Lossless packet behaviour is comparable to TCP (reliability, arrive in order)\n     * but with packets instead of a stream.\n     *\n     * @param friend_number The friend number of the friend this lossless packet\n     *   should be sent to.\n     * @param data A byte array containing the packet data.\n     * @param length The length of the packet data byte array.\n     *\n     * @return true on success.\n     */\n    bool lossless_packet(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data)\n        with error for custom_packet;\n\n  }\n\n\n  event lossy_packet {\n    /**\n     * @param friend_number The friend number of the friend who sent a lossy packet.\n     * @param data A byte array containing the received packet data.\n     * @param length The length of the packet data byte array.\n     */\n    typedef void(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data);\n  }\n\n\n  event lossless_packet {\n    /**\n     * @param friend_number The friend number of the friend who sent the packet.\n     * @param data A byte array containing the received packet data.\n     * @param length The length of the packet data byte array.\n     */\n    typedef void(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data);\n  }\n\n}\n\n\n\n/*******************************************************************************\n *\n * :: Low-level network information\n *\n ******************************************************************************/\n\n\ninline namespace self {\n\n  uint8_t[PUBLIC_KEY_SIZE] dht_id {\n    /**\n     * Writes the temporary DHT public key of this instance to a byte array.\n     *\n     * This can be used in combination with an externally accessible IP address and\n     * the bound port (from ${udp_port.get}) to run a temporary bootstrap node.\n     *\n     * Be aware that every time a new instance is created, the DHT public key\n     * changes, meaning this cannot be used to run a permanent bootstrap node.\n     *\n     * @param dht_id A memory region of at least $PUBLIC_KEY_SIZE bytes. If this\n     *   parameter is NULL, this function has no effect.\n     */\n    get();\n  }\n\n\n  error for get_port {\n    /**\n     * The instance was not bound to any port.\n     */\n    NOT_BOUND,\n  }\n\n\n  uint16_t udp_port {\n    /**\n     * Return the UDP port this Tox instance is bound to.\n     */\n    get() with error for get_port;\n  }\n\n\n  uint16_t tcp_port {\n    /**\n     * Return the TCP port this Tox instance is bound to. This is only relevant if\n     * the instance is acting as a TCP relay.\n     */\n    get() with error for get_port;\n  }\n\n}\n\n} // class tox\n\n%{\n#include \"tox_old.h\"\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n%}\n"
  },
  {
    "path": "other/apidsl/toxav.in.h",
    "content": "%{\n/* toxav.h\n *\n * Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n * This file is part of Tox.\n *\n * Tox is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Tox is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TOXAV_H\n#define TOXAV_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n%}\n\n/** \\page av Public audio/video API for Tox clients.\n *\n * This API can handle multiple calls. Each call has its state, in very rare\n * occasions the library can change the state of the call without apps knowledge.\n *\n */\n\n/** \\subsection events Events and callbacks\n *\n * As in Core API, events are handled by callbacks. One callback can be\n * registered per event. All events have a callback function type named\n * `toxav_{event}_cb` and a function to register it named `toxav_callback_{event}`.\n * Passing a NULL callback will result in no callback being registered for that\n * event. Only one callback per event can be registered, so if a client needs\n * multiple event listeners, it needs to implement the dispatch functionality\n * itself. Unlike Core API, lack of some event handlers will cause the the\n * library to drop calls before they are started. Hanging up call from a\n * callback causes undefined behaviour.\n *\n */\n\n/** \\subsection threading Threading implications\n *\n * Unlike the Core API, this API is fully thread-safe. The library will ensure\n * the proper synchronization of parallel calls.\n *\n * A common way to run ToxAV (multiple or single instance) is to have a thread,\n * separate from tox instance thread, running a simple ${toxAV.iterate} loop,\n * sleeping for ${toxAV.iteration_interval} * milliseconds on each iteration.\n *\n * An important thing to note is that events are triggered from both tox and\n * toxav thread (see above). Audio and video receive frame events are triggered\n * from toxav thread while all the other events are triggered from tox thread.\n *\n * Tox thread has priority with mutex mechanisms. Any api function can\n * fail if mutexes are held by tox thread in which case they will set SYNC\n * error code.\n */\n\n/**\n * External Tox type.\n */\nclass tox {\n  struct this;\n}\n\n/**\n * ToxAV.\n */\nclass toxAV {\n\n/**\n * The ToxAV instance type. Each ToxAV instance can be bound to only one Tox\n * instance, and Tox instance can have only one ToxAV instance. One must make\n * sure to close ToxAV instance prior closing Tox instance otherwise undefined\n * behaviour occurs. Upon closing of ToxAV instance, all active calls will be\n * forcibly terminated without notifying peers.\n *\n */\nstruct this;\n/*******************************************************************************\n *\n * :: API version\n *\n ******************************************************************************/\n/**\n * The major version number. Incremented when the API or ABI changes in an\n * incompatible way.\n */\n#define TOXAV_VERSION_MAJOR               0u\n/**\n * The minor version number. Incremented when functionality is added without\n * breaking the API or ABI. Set to 0 when the major version number is\n * incremented.\n */\n#define TOXAV_VERSION_MINOR               0u\n/**\n * The patch or revision number. Incremented when bugfixes are applied without\n * changing any functionality or API or ABI.\n */\n#define TOXAV_VERSION_PATCH               0u\n\n/**\n * A macro to check at preprocessing time whether the client code is compatible\n * with the installed version of ToxAV.\n */\n#define TOXAV_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH)        \\\n  (TOXAV_VERSION_MAJOR == MAJOR &&                                \\\n   (TOXAV_VERSION_MINOR > MINOR ||                                \\\n    (TOXAV_VERSION_MINOR == MINOR &&                              \\\n     TOXAV_VERSION_PATCH >= PATCH)))\n\n/**\n * A macro to make compilation fail if the client code is not compatible with\n * the installed version of ToxAV.\n */\n#define TOXAV_VERSION_REQUIRE(MAJOR, MINOR, PATCH)                \\\n  typedef char toxav_required_version[TOXAV_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1]\n\n/**\n * A convenience macro to call ${version.is_compatible} with the currently\n * compiling API version.\n */\n#define TOXAV_VERSION_IS_ABI_COMPATIBLE()                         \\\n  toxav_version_is_compatible(TOXAV_VERSION_MAJOR, TOXAV_VERSION_MINOR, TOXAV_VERSION_PATCH)\n\n\nstatic namespace version {\n\n  /**\n   * Return the major version number of the library. Can be used to display the\n   * ToxAV library version or to check whether the client is compatible with the\n   * dynamically linked version of ToxAV.\n   */\n  uint32_t major();\n\n  /**\n   * Return the minor version number of the library.\n   */\n  uint32_t minor();\n\n  /**\n   * Return the patch number of the library.\n   */\n  uint32_t patch();\n\n  /**\n   * Return whether the compiled library version is compatible with the passed\n   * version numbers.\n   */\n  bool is_compatible(uint32_t major, uint32_t minor, uint32_t patch);\n\n}\n/*******************************************************************************\n *\n * :: Creation and destruction\n *\n ******************************************************************************/\n/**\n * Start new A/V session. There can only be only one session per Tox instance.\n */\nstatic this new (tox::this *tox) {\n  NULL,\n  /**\n   * Memory allocation failure while trying to allocate structures required for\n   * the A/V session.\n   */\n  MALLOC,\n  /**\n   * Attempted to create a second session for the same Tox instance.\n   */\n  MULTIPLE,\n}\n/**\n * Releases all resources associated with the A/V session.\n *\n * If any calls were ongoing, these will be forcibly terminated without\n * notifying peers. After calling this function, no other functions may be\n * called and the av pointer becomes invalid.\n */\nvoid kill();\n/**\n * Returns the Tox instance the A/V object was created for.\n */\ntox::this *tox { get(); }\n/*******************************************************************************\n * \n * :: A/V event loop\n *\n ******************************************************************************/\n/**\n * Returns the interval in milliseconds when the next toxav_iterate call should\n * be. If no call is active at the moment, this function returns 200.\n */\nconst uint32_t iteration_interval();\n/**\n * Main loop for the session. This function needs to be called in intervals of\n * toxav_iteration_interval() milliseconds. It is best called in the separate \n * thread from tox_iterate.\n */\nvoid iterate();\n/*******************************************************************************\n * \n * :: Call setup\n *\n ******************************************************************************/\n/**\n * Call a friend. This will start ringing the friend.\n *\n * It is the client's responsibility to stop ringing after a certain timeout,\n * if such behaviour is desired. If the client does not stop ringing, the\n * library will not stop until the friend is disconnected. Audio and video \n * receiving are both enabled by default.\n *\n * @param friend_number The friend number of the friend that should be called.\n * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable\n * audio sending.\n * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable\n * video sending.\n */\nbool call(uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate) {\n  /**\n   * A resource allocation error occurred while trying to create the structures\n   * required for the call.\n   */\n  MALLOC,\n  /**\n   * Synchronization error occurred.\n   */\n  SYNC,\n  /**\n   * The friend number did not designate a valid friend.\n   */\n  FRIEND_NOT_FOUND,\n  /**\n   * The friend was valid, but not currently connected.\n   */\n  FRIEND_NOT_CONNECTED,\n  /**\n   * Attempted to call a friend while already in an audio or video call with\n   * them.\n   */\n  FRIEND_ALREADY_IN_CALL,\n  /**\n   * Audio or video bit rate is invalid.\n   */\n  INVALID_BIT_RATE,\n}\nevent call {\n  /**\n   * The function type for the ${event call} callback.\n   * \n   * @param friend_number The friend number from which the call is incoming.\n   * @param audio_enabled True if friend is sending audio.\n   * @param video_enabled True if friend is sending video.\n   */\n  typedef void(uint32_t friend_number, bool audio_enabled, bool video_enabled);\n}\n/**\n * Accept an incoming call.\n *\n * If answering fails for any reason, the call will still be pending and it is\n * possible to try and answer it later. Audio and video receiving are both\n * enabled by default.\n *\n * @param friend_number The friend number of the friend that is calling.\n * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable\n * audio sending.\n * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable\n * video sending.\n */\nbool answer(uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate) {\n  /**\n   * Synchronization error occurred.\n   */\n  SYNC,\n  /**\n   * Failed to initialize codecs for call session. Note that codec initiation\n   * will fail if there is no receive callback registered for either audio or\n   * video.\n   */\n  CODEC_INITIALIZATION,\n  /**\n   * The friend number did not designate a valid friend.\n   */\n  FRIEND_NOT_FOUND,\n  /**\n   * The friend was valid, but they are not currently trying to initiate a call.\n   * This is also returned if this client is already in a call with the friend.\n   */\n  FRIEND_NOT_CALLING,\n  /**\n   * Audio or video bit rate is invalid.\n   */\n  INVALID_BIT_RATE,\n}\n/*******************************************************************************\n * \n * :: Call state graph\n *\n ******************************************************************************/\nbitmask FRIEND_CALL_STATE {\n  /**\n   * Set by the AV core if an error occurred on the remote end or if friend \n   * timed out. This is the final state after which no more state\n   * transitions can occur for the call. This call state will never be triggered\n   * in combination with other call states.\n   */\n  ERROR,\n  /**\n   * The call has finished. This is the final state after which no more state\n   * transitions can occur for the call. This call state will never be \n   * triggered in combination with other call states.\n   */\n  FINISHED,\n  /**\n   * The flag that marks that friend is sending audio.\n   */\n  SENDING_A,\n  /**\n   * The flag that marks that friend is sending video.\n   */\n  SENDING_V,\n  /**\n   * The flag that marks that friend is receiving audio.\n   */\n  ACCEPTING_A,\n  /**\n   * The flag that marks that friend is receiving video.\n   */\n  ACCEPTING_V,\n}\nevent call_state {\n /**\n  * The function type for the ${event call_state} callback.\n  *\n  * @param friend_number The friend number for which the call state changed.\n  * @param state The bitmask of the new call state which is guaranteed to be\n  * different than the previous state. The state is set to 0 when the call is\n  * paused. The bitmask represents all the activities currently performed by the\n  * friend.\n  */\n  typedef void(uint32_t friend_number, uint32_t state);\n}\n/*******************************************************************************\n * \n * :: Call control\n *\n ******************************************************************************/\nenum class CALL_CONTROL {\n    /**\n     * Resume a previously paused call. Only valid if the pause was caused by this\n     * client, if not, this control is ignored. Not valid before the call is accepted.\n     */\n    RESUME,\n    /**\n     * Put a call on hold. Not valid before the call is accepted.\n     */\n    PAUSE,\n    /**\n     * Reject a call if it was not answered, yet. Cancel a call after it was\n     * answered.\n     */\n    CANCEL,\n    /**\n     * Request that the friend stops sending audio. Regardless of the friend's\n     * compliance, this will cause the ${event audio.receive_frame} event to stop being\n     * triggered on receiving an audio frame from the friend.\n     */\n    MUTE_AUDIO,\n    /**\n     * Calling this control will notify client to start sending audio again.\n     */\n    UNMUTE_AUDIO,\n    /**\n     * Request that the friend stops sending video. Regardless of the friend's\n     * compliance, this will cause the ${event video.receive_frame} event to stop being\n     * triggered on receiving a video frame from the friend.\n     */\n    HIDE_VIDEO,\n    /**\n     * Calling this control will notify client to start sending video again.\n     */\n    SHOW_VIDEO,\n}\n/**\n * Sends a call control command to a friend.\n *\n * @param friend_number The friend number of the friend this client is in a call\n * with.\n * @param control The control command to send.\n *\n * @return true on success.\n */\nbool call_control (uint32_t friend_number, CALL_CONTROL control) {\n  /**\n   * Synchronization error occurred.\n   */\n  SYNC,\n  /**\n   * The friend_number passed did not designate a valid friend.\n   */\n  FRIEND_NOT_FOUND,\n  /**\n   * This client is currently not in a call with the friend. Before the call is\n   * answered, only CANCEL is a valid control.\n   */\n  FRIEND_NOT_IN_CALL,\n  /**\n   * Happens if user tried to pause an already paused call or if trying to\n   * resume a call that is not paused.\n   */\n  INVALID_TRANSITION,\n}\n/*******************************************************************************\n * \n * :: Controlling bit rates\n *\n ******************************************************************************/\nnamespace bit_rate {\n    /**\n     * Set the bit rate to be used in subsequent audio/video frames.\n     *\n     * @param friend_number The friend number of the friend for which to set the\n     * bit rate.\n     * @param audio_bit_rate The new audio bit rate in Kb/sec. Set to 0 to disable\n     * audio sending. Set to -1 to leave unchanged.\n     * @param video_bit_rate The new video bit rate in Kb/sec. Set to 0 to disable\n     * video sending. Set to -1 to leave unchanged.\n     * \n     */\n    bool set(uint32_t friend_number, int32_t audio_bit_rate, int32_t video_bit_rate) {\n        /**\n         * Synchronization error occurred.\n         */\n        SYNC,\n        /**\n         * The audio bit rate passed was not one of the supported values.\n         */\n        INVALID_AUDIO_BIT_RATE,\n        /**\n         * The video bit rate passed was not one of the supported values.\n         */\n         INVALID_VIDEO_BIT_RATE,\n        /**\n         * The friend_number passed did not designate a valid friend.\n         */\n        FRIEND_NOT_FOUND,\n        /**\n         * This client is currently not in a call with the friend.\n         */\n        FRIEND_NOT_IN_CALL,\n    }\n    event status {\n        /**\n         * The function type for the ${event status} callback. The event is triggered\n         * when the network becomes too saturated for current bit rates at which \n         * point core suggests new bit rates.\n         * \n         * @param friend_number The friend number of the friend for which to set the\n         * bit rate.\n         * @param audio_bit_rate Suggested maximum audio bit rate in Kb/sec.\n         * @param video_bit_rate Suggested maximum video bit rate in Kb/sec.\n         */\n        typedef void(uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate);\n    }\n}\n/*******************************************************************************\n * \n * :: A/V sending\n *\n ******************************************************************************/\nerror for send_frame {\n  /**\n   * In case of video, one of Y, U, or V was NULL. In case of audio, the samples\n   * data pointer was NULL.\n   */\n  NULL,\n  /**\n   * The friend_number passed did not designate a valid friend.\n   */\n  FRIEND_NOT_FOUND,\n  /**\n   * This client is currently not in a call with the friend.\n   */\n  FRIEND_NOT_IN_CALL,\n  /**\n   * Synchronization error occurred.\n   */\n  SYNC,\n  /**\n   * One of the frame parameters was invalid. E.g. the resolution may be too\n   * small or too large, or the audio sampling rate may be unsupported.\n   */\n  INVALID,\n  /**\n   * Either friend turned off audio or video receiving or we turned off sending\n   * for the said payload.\n   */\n  PAYLOAD_TYPE_DISABLED,\n  /**\n   * Failed to push frame through rtp interface.\n   */\n  RTP_FAILED,\n}\nnamespace audio {\n  /**\n   * Send an audio frame to a friend.\n   *\n   * The expected format of the PCM data is: [s1c1][s1c2][...][s2c1][s2c2][...]...\n   * Meaning: sample 1 for channel 1, sample 1 for channel 2, ...\n   * For mono audio, this has no meaning, every sample is subsequent. For stereo,\n   * this means the expected format is LRLRLR... with samples for left and right\n   * alternating.\n   *\n   * @param friend_number The friend number of the friend to which to send an\n   * audio frame.\n   * @param pcm An array of audio samples. The size of this array must be\n   * sample_count * channels.\n   * @param sample_count Number of samples in this frame. Valid numbers here are\n   * ((sample rate) * (audio length) / 1000), where audio length can be\n   * 2.5, 5, 10, 20, 40 or 60 millseconds.\n   * @param channels Number of audio channels. Supported values are 1 and 2.\n   * @param sampling_rate Audio sampling rate used in this frame. Valid sampling\n   * rates are 8000, 12000, 16000, 24000, or 48000.\n   */\n  bool send_frame(uint32_t friend_number, const int16_t *pcm, size_t sample_count, \n                  uint8_t channels, uint32_t sampling_rate) with error for send_frame;\n}\nnamespace video {\n  /**\n   * Send a video frame to a friend.\n   *\n   * Y - plane should be of size: height * width\n   * U - plane should be of size: (height/2) * (width/2)\n   * V - plane should be of size: (height/2) * (width/2)\n   *\n   * @param friend_number The friend number of the friend to which to send a video\n   * frame.\n   * @param width Width of the frame in pixels.\n   * @param height Height of the frame in pixels.\n   * @param y Y (Luminance) plane data.\n   * @param u U (Chroma) plane data.\n   * @param v V (Chroma) plane data.\n   */\n  bool send_frame(uint32_t friend_number, uint16_t width, uint16_t height,\n                  const uint8_t *y, const uint8_t *u, const uint8_t *v) with error for send_frame;\n}\n/*******************************************************************************\n * \n * :: A/V receiving\n *\n ******************************************************************************/\nnamespace audio {\n  event receive_frame {\n    /**\n     * The function type for the ${event receive_frame} callback. The callback can be\n     * called multiple times per single iteration depending on the amount of queued\n     * frames in the buffer. The received format is the same as in send function.\n     * \n     * @param friend_number The friend number of the friend who sent an audio frame.\n     * @param pcm An array of audio samples (sample_count * channels elements).\n     * @param sample_count The number of audio samples per channel in the PCM array.\n     * @param channels Number of audio channels.\n     * @param sampling_rate Sampling rate used in this frame.\n     *\n     */\n    typedef void(uint32_t friend_number, const int16_t *pcm, size_t sample_count,\n                 uint8_t channels, uint32_t sampling_rate);\n  }\n}\nnamespace video {\n  event receive_frame {\n    /**\n     * The function type for the ${event receive_frame} callback.\n     *\n     * @param friend_number The friend number of the friend who sent a video frame.\n     * @param width Width of the frame in pixels.\n     * @param height Height of the frame in pixels.\n     * @param y \n     * @param u \n     * @param v Plane data.\n     *          The size of plane data is derived from width and height where\n     *          Y = MAX(width, abs(ystride)) * height, \n     *          U = MAX(width/2, abs(ustride)) * (height/2) and \n     *          V = MAX(width/2, abs(vstride)) * (height/2).\n     * @param ystride\n     * @param ustride\n     * @param vstride Strides data. Strides represent padding for each plane\n     *                that may or may not be present. You must handle strides in\n     *                your image processing code. Strides are negative if the \n     *                image is bottom-up hence why you MUST abs() it when\n     *                calculating plane buffer size.\n     */\n    typedef void(uint32_t friend_number, uint16_t width, uint16_t height,\n                 const uint8_t *y, const uint8_t *u, const uint8_t *v,\n                 int32_t ystride, int32_t ustride, int32_t vstride);\n  }\n}\n\n}\n\n%{\n/**\n * NOTE Compatibility with old toxav group calls TODO remove\n */\n/* Create a new toxav group.\n *\n * return group number on success.\n * return -1 on failure.\n *\n * Audio data callback format:\n *   audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n */\nint toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t,\n                           unsigned int, void *), void *userdata);\n\n/* Join a AV group (you need to have been invited first.)\n *\n * returns group number on success\n * returns -1 on failure.\n *\n * Audio data callback format (same as the one for toxav_add_av_groupchat()):\n *   audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n */\nint toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length,\n                            void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata);\n\n/* Send audio to the group chat.\n *\n * return 0 on success.\n * return -1 on failure.\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n *\n * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000)\n * Valid number of channels are 1 or 2.\n * Valid sample rates are 8000, 12000, 16000, 24000, or 48000.\n *\n * Recommended values are: samples = 960, channels = 1, sample_rate = 48000\n */\nint toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,\n                           unsigned int sample_rate);\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* TOXAV_H */\n%}\n"
  },
  {
    "path": "other/astyle/README.md",
    "content": "This directory can house various tools and utilities.\n\n# How to use astyle\n\n## Manually\n\n### For all files\n\nRun from ``toxcore`` directory:\n```bash\nastyle --options=./other/astyle/astylerc ./toxcore/*.c ./toxcore/*.h ./toxdns/*.c ./toxdns/*.h ./testing/*.c ./toxav/*.c ./toxav/*.h ./other/*.c ./other/bootstrap_daemon/*.c ./toxencryptsave/*.c ./toxencryptsave/*.h ./auto_tests/*.c\n```\n\n### For selected file\n\nRun from ``toxcore`` directory, e.g. for [``tox.h``](/toxcore/tox.h) file:\n```bash\nastyle --options=./other/astyle/astylerc ./toxcore/tox.h\n```\n\n\n## Automatically, as pre-commit hook (*NIX only)\n\nCopy [``astylerc``](/other/astyle/astylerc) to ``toxcore/.git/hooks``\n\n\n\n# Why\n\n``astylerc`` - this file can be used in the pre-commit hook to try its best at making the code conform to the coding style of toxcore.\n\nFurthermore, it is being used to format ``tox.h`` after using [``apidsl``](/other/apidsl) to generate it."
  },
  {
    "path": "other/astyle/astylerc",
    "content": "--style=kr\n        --pad-header\n        --max-code-length=120\n                          --convert-tabs\n                          --indent-switches\n                          --pad-oper\n                          --align-pointer=name\n                                  --align-reference=name\n                                          --preserve-date\n                                          --lineend=linux\n                                                  --break-blocks"
  },
  {
    "path": "other/astyle/pre-commit",
    "content": "#!/usr/bin/env sh\n#\n# An example hook script to verify what is about to be committed.\n# Called by \"git commit\" with no arguments.  The hook should\n# exit with non-zero status after issuing an appropriate message if\n# it wants to stop the commit.\n#\n# To enable this hook, rename this file to \"pre-commit\".\n\nfor file in `git diff-index --diff-filter=ACMR --name-only HEAD`; do\n    if [[ $file == *.c || $file == *.h ]]\n    then\n        echo $file\n        `which astyle` $file --options=tools/astylerc\n        git add $file\n    fi\ndone"
  },
  {
    "path": "other/bootstrap_daemon/README.md",
    "content": "#Instructions\n\n- [For `systemd` users](#systemd)\n  - [Setting up](#systemd-setting-up)\n  - [Updating](#systemd-updating)\n  - [Troubleshooting](#systemd-troubleshooting)\n<br>\n- [For `SysVinit` users](#sysvinit)\n  - [Setting up](#sysvinit-setting-up)\n  - [Updating](#sysvinit-updating)\n  - [Troubleshooting](#sysvinit-troubleshooting)\n<br>\n- [For `Docker` users](#docker)\n  - [Setting up](#docker-setting-up)\n  - [Updating](#docker-updating)\n  - [Troubleshooting](#docker-troubleshooting)\n\n\nThese instructions are primarily tested on Debian Linux, Wheezy for SysVinit and Jessie for systemd, but they should work on other POSIX-compliant systems too.\n\n\n<a name=\"systemd\" />\n##For `systemd` users\n\n<a name=\"systemd-setting-up\" />\n###Setting up\n\nFor security reasons we run the daemon under its own user.\n\nCreate a new user by executing the following:\n```sh\nsudo 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\n```\n\nRestrict access to home directory:\n```sh\nsudo chmod 700 /var/lib/tox-bootstrapd\n```\n\nCopy `tox-bootstrapd.conf` file to where `ExecStart=` from `tox-bootstrapd.service` points to. By default it's `/etc/tox-bootstrapd.conf`.\n```sh\nsudo cp tox-bootstrapd.conf /etc/tox-bootstrapd.conf\n```\n\nGo over everything in the copied `tox-bootstrapd.conf` file. Set options you want and add actual working nodes to the `bootstrap_nodes` list, instead of the example ones, if you want your node to connect to the Tox network. Make sure `pid_file_path` matches `PIDFile=` from `tox-bootstrapd.service`.\n\nCopy `tox-bootstrapd.service` to `/etc/systemd/system/`:\n```sh\nsudo cp tox-bootstrapd.service /etc/systemd/system/\n```\n\nYou must uncomment the next line in tox-bootstrapd.service, if you want to use port number < 1024 \n\n    #CapabilityBoundingSet=CAP_NET_BIND_SERVICE\n\nand, possibly, install `libcap2-bin` or `libcap2` package, depending of your distribution.\n\nReload systemd units definitions, enable service for automatic start (if needed), start it and verify it's running: \n```sh\nsudo systemctl daemon-reload\nsudo systemctl enable tox-bootstrapd.service\nsudo systemctl start tox-bootstrapd.service\nsudo systemctl status tox-bootstrapd.service\n```\n\nGet your public key and check that the daemon initialized correctly:\n```sh\nsudo grep \"tox-bootstrapd\" /var/log/syslog\n```\n\n<a name=\"systemd-updating\" />\n###Updating\n\nYou want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.\n\nTo update the daemon first stop it:\n\n```sh\nsudo systemctl stop tox-bootstrapd.service\n```\n\nThen update your toxcore git repository, rebuild the toxcore and the daemon and make sure to install them.\n\nCheck if `tox-bootstrapd.service` in toxcore git repository was modified since the last time you copied it, as you might need to update it too.\n\nAfter all of this is done, simply start the daemon back again:\n\n```sh\nsudo systemctl start tox-bootstrapd.service\n```\n\nNote that `tox-bootstrapd.service` file might\n\n<a name=\"systemd-troubleshooting\" />\n###Troubleshooting\n\n- Check daemon's status:\n```sh\nsudo systemctl status tox-bootstrapd.service\n```\n\n- Check the log for errors:\n```sh\nsudo grep \"tox-bootstrapd\" /var/log/syslog\n# or\nsudo journalctl --pager-end\n# or\nsudo journalctl -f _SYSTEMD_UNIT=tox-bootstrapd.service\n```\n\n- Make sure tox-bootstrapd user has write permission for keys and pid files.\n\n- Make sure tox-bootstrapd has read permission for the config file.\n\n- Make sure tox-bootstrapd location matches its path in tox-bootstrapd.service file.\n\n\n<a name=\"sysvinit\" />\n##For `SysVinit` users\n\n<a name=\"sysvinit-setting-up\" />\n###Setting up\n\nFor security reasons we run the daemon under its own user.\n\nCreate a new user by executing the following:\n```sh\nsudo 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\n```\n\nRestrict access to home directory:\n```sh\nsudo chmod 700 /var/lib/tox-bootstrapd\n```\n\nCopy `tox-bootstrapd.conf` file to where `CFGFILE` variable from `tox-bootstrapd.sh` points to. By default it's `/etc/tox-bootstrapd.conf`.\n```sh\nsudo cp tox-bootstrapd.conf /etc/tox-bootstrapd.conf\n```\n\nGo over everything in the copied `tox-bootstrapd.conf` file. Set options you want and add actual working nodes to the `bootstrap_nodes` list, instead of the example ones, if you want your node to connect to the Tox network. Make sure `pid_file_path` matches `PIDFILE` from `tox-bootstrapd.sh`.\n\nLook 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 on your system. The default values must be fine for most users and we assume that you use those next.\n\nIf you have configured the daemon to use any port numbers that are lower than 1024, you need to execute the command below, as by default non-privileged users cannot open ports <1024. The change persists through reboot:\n\n```sh\nsudo setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/tox-bootstrapd\n```\n\nCopy `tox-bootstrapd.sh` init script to `/etc/init.d/tox-bootstrapd` (note the disappearance of \".sh\" ending):\n```sh\nsudo cp tox-bootstrapd.sh /etc/init.d/tox-bootstrapd\n```\n\nSet permissions for the init system to run the script:\n```sh\nsudo chmod 755 /etc/init.d/tox-bootstrapd\n```\n\nMake the init system aware of the script, start the daemon and verify it's running:\n```sh\nsudo update-rc.d tox-bootstrapd defaults\nsudo service tox-bootstrapd start\nsudo service tox-bootstrapd status\n```\n\nGet your public key and check that the daemon initialized correctly:\n```sh\nsudo grep \"tox-bootstrapd\" /var/log/syslog\n```\n\n<a name=\"sysvinit-updating\" />\n###Updating\n\nYou want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.\n\nTo update the daemon first stop it:\n\n```sh\nsudo service tox-bootstrapd stop\n```\n\nThen update your toxcore git repository, rebuild the toxcore and the daemon and make sure to install them.\n\nCheck if `tox-bootstrapd.sh` in toxcore git repository was modified since the last time you copied it, as you might need to update it too.\n\nAfter all of this is done, simply start the daemon back again:\n\n```sh\nsudo service tox-bootstrapd start\n```\n\n<a name=\"sysvinit-troubleshooting\" />\n###Troubleshooting\n\n- Check daemon's status:\n```sh\nsudo service tox-bootstrapd status\n```\n\n- Check the log for errors: \n```sh\nsudo grep \"tox-bootstrapd\" /var/log/syslog\n```\n\n- Check that variables in the beginning of `/etc/init.d/tox-bootstrapd` are valid.\n\n- Make sure tox-bootstrapd user has write permission for keys and pid files.\n\n- Make sure tox-bootstrapd has read permission for the config file.\n\n- Make sure tox-bootstrapd location matches its path in the `/etc/init.d/tox-bootstrapd` init script.\n\n\n<a name=\"docker\" />\n##For `Docker` users:\n\n<a name=\"docker-setting-up\" />\n###Setting up\n\nIf you are familiar with Docker and would rather run the daemon in a Docker container, run the following from this directory:\n\n```sh\nsudo docker build -t tox-bootstrapd docker/\n\nsudo 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\nsudo chmod 700 /var/lib/tox-bootstrapd\n\nsudo docker run -d --name tox-bootstrapd --restart always -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ -p 443:443 -p 3389:3389 -p 33445:33445 -p 33445:33445/udp tox-bootstrapd\n```\n\nWe create a new user and protect its home directory in order to mount it in the Docker image, so that the kyepair the daemon uses would be stored on the host system, which makes it less likely that you would loose the keypair while playing with or updating the Docker container.\n\nYou can check logs for your public key or any errors:\n```sh\nsudo docker logs tox-bootstrapd\n```\n\nNote that the Docker container runs a script which pulls a list of bootstrap nodes off https://nodes.tox.chat/ and adds them in the config file.\n\n<a name=\"docker-updating\" />\n###Updating\n\nYou want to make sure that the daemon uses the newest toxcore, as there might have been some changes done to the DHT, so it's advised to update the daemon at least once every month.\n\nTo update the daemon, all you need is to erase current container with its image:\n\n```sh\nsudo docker stop tox-bootstrapd\nsudo docker rm tox-bootstrapd\nsudo docker rmi tox-bootstrapd\n```\n\nThen rebuild and run the image again:\n\n```sh\nsudo docker build -t tox-bootstrapd docker/\nsudo docker run -d --name tox-bootstrapd --restart always -v /var/lib/tox-bootstrapd/:/var/lib/tox-bootstrapd/ -p 443:443 -p 3389:3389 -p 33445:33445 -p 33445:33445/udp tox-bootstrapd\n```\n\n<a name=\"docker-troubleshooting\" />\n###Troubleshooting\n\n- Check if the container is running:\n```sh\nsudo docker ps -a\n```\n\n- Check the log for errors:\n```sh\nsudo docker logs tox-bootstrapd\n```\n"
  },
  {
    "path": "other/bootstrap_daemon/docker/Dockerfile",
    "content": "FROM debian:jessie\n\nWORKDIR /tmp/tox\n\nRUN export BUILD_PACKAGES=\"\\\n      build-essential \\\n      libtool \\\n      autotools-dev \\\n      automake \\\n      checkinstall \\\n      check \\\n      git \\\n      yasm \\\n      libsodium-dev \\\n      libconfig-dev \\\n      python3\" && \\\n    export RUNTIME_PACKAGES=\"\\\n      libconfig9 \\\n      libsodium13\" && \\\n# get all deps\n    apt-get update && apt-get install -y $BUILD_PACKAGES $RUNTIME_PACKAGES && \\\n# install toxcore and daemon\n    git clone https://github.com/irungentoo/toxcore && \\\n    cd toxcore && \\\n    ./autogen.sh && \\\n    ./configure --enable-daemon && \\\n    make -j`nproc` && \\\n    make install -j`nproc` && \\\n    ldconfig && \\\n# add new user\n    useradd --home-dir /var/lib/tox-bootstrapd --create-home \\\n      --system --shell /sbin/nologin \\\n      --comment \"Account to run Tox's DHT bootstrap daemon\" \\\n      --user-group tox-bootstrapd && \\\n    chmod 700 /var/lib/tox-bootstrapd && \\\n    cp other/bootstrap_daemon/tox-bootstrapd.conf /etc/tox-bootstrapd.conf && \\\n# remove all the example bootstrap nodes from the config file\n    sed -i '/^bootstrap_nodes = /,$d' /etc/tox-bootstrapd.conf && \\\n# add bootstrap nodes from https://nodes.tox.chat/\n    python3 other/bootstrap_daemon/docker/get-nodes.py >> /etc/tox-bootstrapd.conf && \\\n# perform cleanup\n    export AUTO_ADDED_PACKAGES=\"$(apt-mark showauto)\" && \\\n    apt-get remove --purge -y $BUILD_PACKAGES $AUTO_ADDED_PACKAGES && \\\n    apt-get clean && \\\n    rm -rf /var/lib/apt/lists/* && \\\n    cd / && \\\n    rm -rf /tmp/*\n\nWORKDIR /var/lib/tox-bootstrapd\n\nUSER tox-bootstrapd\n\nENTRYPOINT /usr/local/bin/tox-bootstrapd \\\n             --config /etc/tox-bootstrapd.conf \\\n             --log-backend stdout \\\n             --foreground\n\nEXPOSE 443/tcp 3389/tcp 33445/tcp 33445/udp\n"
  },
  {
    "path": "other/bootstrap_daemon/docker/get-nodes.py",
    "content": "#!/usr/bin/env python3\n\"\"\"\nCopyright (c) 2016 by nurupo <nurupo.contributions@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\"\"\"\n\n# Gets a list of nodes from https://nodes.tox.chat/json and prints them out\n# in the format of tox-bootstrapd config file.\n\nimport urllib.request\nimport json\n\nresponse = urllib.request.urlopen('https://nodes.tox.chat/json')\nraw_json = response.read().decode('ascii', 'ignore')\nnodes = json.loads(raw_json)['nodes']\n\noutput = 'bootstrap_nodes = (\\n'\n\nfor node in nodes:\n    node_output  = '  { // ' + node['maintainer'] + '\\n'\n    node_output += '    public_key = \"' + node['public_key'] + '\"\\n'\n    node_output += '    port = ' + str(node['port']) + '\\n'\n    node_output += '    address = \"'\n    if len(node['ipv4']) > 4:\n        output += node_output + node['ipv4'] + '\"\\n  },\\n'\n    if len(node['ipv6']) > 4:\n        output += node_output + node['ipv6'] + '\"\\n  },\\n'\n\n# remove last comma\noutput = output[:-2] + '\\n)\\n'\n\nprint(output)\n"
  },
  {
    "path": "other/bootstrap_daemon/src/Makefile.inc",
    "content": "if BUILD_DHT_BOOTSTRAP_DAEMON\n\nbin_PROGRAMS += tox-bootstrapd\n\ntox_bootstrapd_SOURCES = \\\n                        ../other/bootstrap_daemon/src/command_line_arguments.c \\\n                        ../other/bootstrap_daemon/src/command_line_arguments.h \\\n                        ../other/bootstrap_daemon/src/config.c \\\n                        ../other/bootstrap_daemon/src/config_defaults.h \\\n                        ../other/bootstrap_daemon/src/config.h \\\n                        ../other/bootstrap_daemon/src/log.c \\\n                        ../other/bootstrap_daemon/src/log.h \\\n                        ../other/bootstrap_daemon/src/tox-bootstrapd.c \\\n                        ../other/bootstrap_daemon/src/global.h \\\n                        ../other/bootstrap_node_packets.c \\\n                        ../other/bootstrap_node_packets.h\n\n\ntox_bootstrapd_CFLAGS = \\\n                        -I$(top_srcdir)/other/bootstrap_daemon \\\n                        $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS) \\\n                        $(LIBCONFIG_CFLAGS)\n\ntox_bootstrapd_LDADD = \\\n                        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBCONFIG_LIBS) \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_LIBS)\n\nendif\n\nEXTRA_DIST += \\\n    $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.conf \\\n    $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.service \\\n    $(top_srcdir)/other/bootstrap_daemon/tox-bootstrapd.sh\n    \n"
  },
  {
    "path": "other/bootstrap_daemon/src/command_line_arguments.c",
    "content": "/* command_line_arguments.c\n *\n * Tox DHT bootstrap daemon.\n * Command line argument handling.\n *\n *  Copyright (C) 2015-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#include \"command_line_arguments.h\"\n\n#include \"global.h\"\n\n#include <getopt.h>\n\n#include <stdlib.h>\n#include <string.h>\n\n\n/**\n * Prints --help message\n */\nvoid print_help()\n{\n    // 2 space ident\n    // make sure all lines fit into 80 columns\n    // make sure options are listed in alphabetical order\n    write_log(LOG_LEVEL_INFO,\n              \"Usage: tox-bootstrapd [OPTION]... --config=FILE_PATH\\n\"\n              \"\\n\"\n              \"Options:\\n\"\n              \"  --config=FILE_PATH     Specify path to the config file.\\n\"\n              \"                         This is a required option.\\n\"\n              \"                         Set FILE_PATH to a path to an empty file in order to\\n\"\n              \"                         use default settings.\\n\"\n              \"  --foreground           Run the daemon in foreground. The daemon won't fork\\n\"\n              \"                         (detach from the terminal) and won't use the PID file.\\n\"\n              \"  --help                 Print this help message.\\n\"\n              \"  --log-backend=BACKEND  Specify which logging backend to use.\\n\"\n              \"                         Valid BACKEND values (case sensetive):\\n\"\n              \"                           syslog Writes log messages to syslog.\\n\"\n              \"                                  Default option when no --log-backend is\\n\"\n              \"                                  specified.\\n\"\n              \"                           stdout Writes log messages to stdout/stderr.\\n\"\n              \"  --version              Print version information.\\n\");\n}\n\nvoid handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend,\n                                   bool *run_in_foreground)\n{\n    if (argc < 2) {\n        write_log(LOG_LEVEL_ERROR, \"Error: No arguments provided.\\n\\n\");\n        print_help();\n        exit(1);\n    }\n\n    opterr = 0;\n\n    static struct option long_options[] = {\n        {\"config\",      required_argument, 0, 'c'}, // required option\n        {\"foreground\",  no_argument,       0, 'f'},\n        {\"help\",        no_argument,       0, 'h'},\n        {\"log-backend\", required_argument, 0, 'l'}, // optional, defaults to syslog\n        {\"version\",     no_argument,       0, 'v'},\n        {0,             0,                 0,  0 }\n    };\n\n    bool cfg_file_path_set = false;\n    bool log_backend_set   = false;\n\n    *run_in_foreground = false;\n\n    int opt;\n\n    while ((opt = getopt_long(argc, argv, \":\", long_options, NULL)) != -1) {\n\n        switch (opt) {\n\n            case 'c':\n                *cfg_file_path = optarg;\n                cfg_file_path_set = true;\n                break;\n\n            case 'f':\n                *run_in_foreground = true;\n                break;\n\n            case 'h':\n                print_help();\n                exit(0);\n\n            case 'l':\n                if (strcmp(optarg, \"syslog\") == 0) {\n                    *log_backend = LOG_BACKEND_SYSLOG;\n                    log_backend_set = true;\n                } else if (strcmp(optarg, \"stdout\") == 0) {\n                    *log_backend = LOG_BACKEND_STDOUT;\n                    log_backend_set = true;\n                } else {\n                    write_log(LOG_LEVEL_ERROR, \"Error: Invalid BACKEND value for --log-backend option passed: %s\\n\\n\", optarg);\n                    print_help();\n                    exit(1);\n                }\n\n                break;\n\n            case 'v':\n                write_log(LOG_LEVEL_INFO, \"Version: %lu\\n\", DAEMON_VERSION_NUMBER);\n                exit(0);\n\n            case '?':\n                write_log(LOG_LEVEL_ERROR, \"Error: Unrecognized option %s\\n\\n\", argv[optind - 1]);\n                print_help();\n                exit(1);\n\n            case ':':\n                write_log(LOG_LEVEL_ERROR, \"Error: No argument provided for option %s\\n\\n\", argv[optind - 1]);\n                print_help();\n                exit(1);\n        }\n    }\n\n    if (!log_backend_set) {\n        *log_backend = LOG_BACKEND_SYSLOG;\n    }\n\n    if (!cfg_file_path_set) {\n        write_log(LOG_LEVEL_ERROR, \"Error: The required --config option wasn't specified\\n\\n\");\n        print_help();\n        exit(1);\n    }\n}\n"
  },
  {
    "path": "other/bootstrap_daemon/src/command_line_arguments.h",
    "content": "/* command_line_arguments.h\n *\n * Tox DHT bootstrap daemon.\n * Command line argument handling.\n *\n *  Copyright (C) 2015-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef COMMAND_LINE_ARGUMENTS_H\n#define COMMAND_LINE_ARGUMENTS_H\n\n#include \"log.h\"\n\n/**\n * Handles command line arguments, setting cfg_file_path and log_backend.\n * Terminates the application if incorrect arguments are specified.\n *\n * @param argc Argc passed into main().\n * @param argv Argv passed into main().\n * @param cfg_file_path Sets to the provided by the user config file path.\n * @param log_backend Sets to the provided by the user log backend option.\n * @param run_in_foreground Sets to the provided by the user foreground option.\n */\nvoid handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground);\n\n#endif // COMMAND_LINE_ARGUMENTS_H\n"
  },
  {
    "path": "other/bootstrap_daemon/src/config.c",
    "content": "/* config.c\n *\n * Tox DHT bootstrap daemon.\n * Functionality related to dealing with the config file.\n *\n *  Copyright (C) 2014-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#include \"config.h\"\n\n#include \"config_defaults.h\"\n#include \"log.h\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <string.h>\n\n#include <libconfig.h>\n\n#include \"../../bootstrap_node_packets.h\"\n\n/**\n * Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array.\n *\n * Supposed to be called from get_general_config only.\n *\n * Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`.\n */\nvoid parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)\n{\n    const char *NAME_TCP_RELAY_PORTS = \"tcp_relay_ports\";\n\n    *tcp_relay_port_count = 0;\n\n    config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);\n\n    if (ports_array == NULL) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in the configuration file.\\n\", NAME_TCP_RELAY_PORTS);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s':\\n\", NAME_TCP_RELAY_PORTS);\n\n        uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};\n\n        int i;\n\n        for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {\n            write_log(LOG_LEVEL_INFO, \"Port #%d: %u\\n\", i, default_ports[i]);\n        }\n\n        // similar procedure to the one of reading config file below\n        *tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));\n\n        for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {\n\n            (*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];\n\n            if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT\n                    || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {\n                write_log(LOG_LEVEL_WARNING, \"Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\\n\", i,\n                          (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);\n                continue;\n            }\n\n            (*tcp_relay_port_count) ++;\n        }\n\n        // the loop above skips invalid ports, so we adjust the allocated memory size\n        if ((*tcp_relay_port_count) > 0) {\n            *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));\n        } else {\n            free(*tcp_relay_ports);\n            *tcp_relay_ports = NULL;\n        }\n\n        return;\n    }\n\n    if (config_setting_is_array(ports_array) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_ERROR, \"'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\\n\",\n                  NAME_TCP_RELAY_PORTS);\n        return;\n    }\n\n    int config_port_count = config_setting_length(ports_array);\n\n    if (config_port_count == 0) {\n        write_log(LOG_LEVEL_ERROR, \"'%s' is empty.\\n\", NAME_TCP_RELAY_PORTS);\n        return;\n    }\n\n    *tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));\n\n    int i;\n\n    for (i = 0; i < config_port_count; i ++) {\n        config_setting_t *elem = config_setting_get_elem(ports_array, i);\n\n        if (elem == NULL) {\n            // 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\n            write_log(LOG_LEVEL_WARNING, \"Port #%d: Something went wrong while parsing the port. Stopping reading ports.\\n\", i);\n            break;\n        }\n\n        if (config_setting_is_number(elem) == CONFIG_FALSE) {\n            write_log(LOG_LEVEL_WARNING, \"Port #%d: Not a number. Skipping.\\n\", i);\n            continue;\n        }\n\n        (*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);\n\n        if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT\n                || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {\n            write_log(LOG_LEVEL_WARNING, \"Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\\n\", i,\n                      (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);\n            continue;\n        }\n\n        (*tcp_relay_port_count) ++;\n    }\n\n    // the loop above skips invalid ports, so we adjust the allocated memory size\n    if ((*tcp_relay_port_count) > 0) {\n        *tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));\n    } else {\n        free(*tcp_relay_ports);\n        *tcp_relay_ports = NULL;\n    }\n}\n\nint get_general_config(const char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port,\n                       int *enable_ipv6,\n                       int *enable_ipv4_fallback, int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports,\n                       int *tcp_relay_port_count, int *enable_motd, char **motd)\n{\n    config_t cfg;\n\n    const char *NAME_PORT                 = \"port\";\n    const char *NAME_PID_FILE_PATH        = \"pid_file_path\";\n    const char *NAME_KEYS_FILE_PATH       = \"keys_file_path\";\n    const char *NAME_ENABLE_IPV6          = \"enable_ipv6\";\n    const char *NAME_ENABLE_IPV4_FALLBACK = \"enable_ipv4_fallback\";\n    const char *NAME_ENABLE_LAN_DISCOVERY = \"enable_lan_discovery\";\n    const char *NAME_ENABLE_TCP_RELAY     = \"enable_tcp_relay\";\n    const char *NAME_ENABLE_MOTD          = \"enable_motd\";\n    const char *NAME_MOTD                 = \"motd\";\n\n    config_init(&cfg);\n\n    // Read the file. If there is an error, report it and exit.\n    if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_ERROR, \"%s:%d - %s\\n\", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));\n        config_destroy(&cfg);\n        return 0;\n    }\n\n    // Get port\n    if (config_lookup_int(&cfg, NAME_PORT, port) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_PORT);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %d\\n\", NAME_PORT, DEFAULT_PORT);\n        *port = DEFAULT_PORT;\n    }\n\n    // Get PID file location\n    const char *tmp_pid_file;\n\n    if (config_lookup_string(&cfg, NAME_PID_FILE_PATH, &tmp_pid_file) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_PID_FILE_PATH);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_PID_FILE_PATH, DEFAULT_PID_FILE_PATH);\n        tmp_pid_file = DEFAULT_PID_FILE_PATH;\n    }\n\n    *pid_file_path = malloc(strlen(tmp_pid_file) + 1);\n    strcpy(*pid_file_path, tmp_pid_file);\n\n    // Get keys file location\n    const char *tmp_keys_file;\n\n    if (config_lookup_string(&cfg, NAME_KEYS_FILE_PATH, &tmp_keys_file) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_KEYS_FILE_PATH);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_KEYS_FILE_PATH, DEFAULT_KEYS_FILE_PATH);\n        tmp_keys_file = DEFAULT_KEYS_FILE_PATH;\n    }\n\n    *keys_file_path = malloc(strlen(tmp_keys_file) + 1);\n    strcpy(*keys_file_path, tmp_keys_file);\n\n    // Get IPv6 option\n    if (config_lookup_bool(&cfg, NAME_ENABLE_IPV6, enable_ipv6) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_ENABLE_IPV6);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_ENABLE_IPV6, DEFAULT_ENABLE_IPV6 ? \"true\" : \"false\");\n        *enable_ipv6 = DEFAULT_ENABLE_IPV6;\n    }\n\n    // Get IPv4 fallback option\n    if (config_lookup_bool(&cfg, NAME_ENABLE_IPV4_FALLBACK, enable_ipv4_fallback) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_ENABLE_IPV4_FALLBACK);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_ENABLE_IPV4_FALLBACK,\n                  DEFAULT_ENABLE_IPV4_FALLBACK ? \"true\" : \"false\");\n        *enable_ipv4_fallback = DEFAULT_ENABLE_IPV4_FALLBACK;\n    }\n\n    // Get LAN discovery option\n    if (config_lookup_bool(&cfg, NAME_ENABLE_LAN_DISCOVERY, enable_lan_discovery) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_ENABLE_LAN_DISCOVERY);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_ENABLE_LAN_DISCOVERY,\n                  DEFAULT_ENABLE_LAN_DISCOVERY ? \"true\" : \"false\");\n        *enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;\n    }\n\n    // Get TCP relay option\n    if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_ENABLE_TCP_RELAY);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_ENABLE_TCP_RELAY,\n                  DEFAULT_ENABLE_TCP_RELAY ? \"true\" : \"false\");\n        *enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;\n    }\n\n    if (*enable_tcp_relay) {\n        parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);\n    } else {\n        *tcp_relay_port_count = 0;\n    }\n\n    // Get MOTD option\n    if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_ENABLE_MOTD);\n        write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_ENABLE_MOTD,\n                  DEFAULT_ENABLE_MOTD ? \"true\" : \"false\");\n        *enable_motd = DEFAULT_ENABLE_MOTD;\n    }\n\n    if (*enable_motd) {\n        // Get MOTD\n        const char *tmp_motd;\n\n        if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {\n            write_log(LOG_LEVEL_WARNING, \"No '%s' setting in configuration file.\\n\", NAME_MOTD);\n            write_log(LOG_LEVEL_WARNING, \"Using default '%s': %s\\n\", NAME_MOTD, DEFAULT_MOTD);\n            tmp_motd = DEFAULT_MOTD;\n        }\n\n        size_t tmp_motd_length = strlen(tmp_motd) + 1;\n        size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;\n        *motd = malloc(motd_length);\n        strncpy(*motd, tmp_motd, motd_length);\n        (*motd)[motd_length - 1] = '\\0';\n    }\n\n    config_destroy(&cfg);\n\n    write_log(LOG_LEVEL_INFO, \"Successfully read:\\n\");\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_PID_FILE_PATH,        *pid_file_path);\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_KEYS_FILE_PATH,       *keys_file_path);\n    write_log(LOG_LEVEL_INFO, \"'%s': %d\\n\", NAME_PORT,                 *port);\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_ENABLE_IPV6,          *enable_ipv6          ? \"true\" : \"false\");\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_ENABLE_IPV4_FALLBACK, *enable_ipv4_fallback ? \"true\" : \"false\");\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? \"true\" : \"false\");\n\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_ENABLE_TCP_RELAY,     *enable_tcp_relay     ? \"true\" : \"false\");\n\n    // show info about tcp ports only if tcp relay is enabled\n    if (*enable_tcp_relay) {\n        if (*tcp_relay_port_count == 0) {\n            write_log(LOG_LEVEL_ERROR, \"No TCP ports could be read.\\n\");\n        } else {\n            write_log(LOG_LEVEL_INFO, \"Read %d TCP ports:\\n\", *tcp_relay_port_count);\n            int i;\n\n            for (i = 0; i < *tcp_relay_port_count; i ++) {\n                write_log(LOG_LEVEL_INFO, \"Port #%d: %u\\n\", i, (*tcp_relay_ports)[i]);\n            }\n        }\n    }\n\n    write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_ENABLE_MOTD,          *enable_motd          ? \"true\" : \"false\");\n\n    if (*enable_motd) {\n        write_log(LOG_LEVEL_INFO, \"'%s': %s\\n\", NAME_MOTD, *motd);\n    }\n\n    return 1;\n}\n\n/**\n *\n * Converts a hex string with even number of characters into binary.\n *\n * Important: You are responsible for freeing the return value.\n *\n * @return binary on success,\n *         NULL on failure.\n */\nuint8_t *hex_string_to_bin(char *hex_string)\n{\n    if (strlen(hex_string) % 2 != 0) {\n        return NULL;\n    }\n\n    size_t len = strlen(hex_string) / 2;\n    uint8_t *ret = malloc(len);\n\n    char *pos = hex_string;\n    size_t i;\n\n    for (i = 0; i < len; ++i, pos += 2) {\n        sscanf(pos, \"%2hhx\", &ret[i]);\n    }\n\n    return ret;\n}\n\nint bootstrap_from_config(const char *cfg_file_path, DHT *dht, int enable_ipv6)\n{\n    const char *NAME_BOOTSTRAP_NODES = \"bootstrap_nodes\";\n\n    const char *NAME_PUBLIC_KEY = \"public_key\";\n    const char *NAME_PORT       = \"port\";\n    const char *NAME_ADDRESS    = \"address\";\n\n    config_t cfg;\n\n    config_init(&cfg);\n\n    if (config_read_file(&cfg, cfg_file_path) == CONFIG_FALSE) {\n        write_log(LOG_LEVEL_ERROR, \"%s:%d - %s\\n\", config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));\n        config_destroy(&cfg);\n        return 0;\n    }\n\n    config_setting_t *node_list = config_lookup(&cfg, NAME_BOOTSTRAP_NODES);\n\n    if (node_list == NULL) {\n        write_log(LOG_LEVEL_WARNING, \"No '%s' setting in the configuration file. Skipping bootstrapping.\\n\",\n                  NAME_BOOTSTRAP_NODES);\n        config_destroy(&cfg);\n        return 1;\n    }\n\n    if (config_setting_length(node_list) == 0) {\n        write_log(LOG_LEVEL_WARNING, \"No bootstrap nodes found. Skipping bootstrapping.\\n\");\n        config_destroy(&cfg);\n        return 1;\n    }\n\n    int bs_port;\n    const char *bs_address;\n    const char *bs_public_key;\n\n    config_setting_t *node;\n\n    int i = 0;\n\n    while (config_setting_length(node_list)) {\n\n        node = config_setting_get_elem(node_list, 0);\n\n        if (node == NULL) {\n            config_destroy(&cfg);\n            return 0;\n        }\n\n        // Check that all settings are present\n        if (config_setting_lookup_string(node, NAME_PUBLIC_KEY, &bs_public_key) == CONFIG_FALSE) {\n            write_log(LOG_LEVEL_WARNING, \"Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\\n\", i,\n                      NAME_PUBLIC_KEY);\n            goto next;\n        }\n\n        if (config_setting_lookup_int(node, NAME_PORT, &bs_port) == CONFIG_FALSE) {\n            write_log(LOG_LEVEL_WARNING, \"Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\\n\", i, NAME_PORT);\n            goto next;\n        }\n\n        if (config_setting_lookup_string(node, NAME_ADDRESS, &bs_address) == CONFIG_FALSE) {\n            write_log(LOG_LEVEL_WARNING, \"Bootstrap node #%d: Couldn't find '%s' setting. Skipping the node.\\n\", i, NAME_ADDRESS);\n            goto next;\n        }\n\n        // Process settings\n        if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES * 2) {\n            write_log(LOG_LEVEL_WARNING, \"Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\\n\", i, NAME_PUBLIC_KEY,\n                      bs_public_key);\n            goto next;\n        }\n\n        if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {\n            write_log(LOG_LEVEL_WARNING, \"Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\\n\", i,\n                      NAME_PORT,\n                      bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);\n            goto next;\n        }\n\n        uint8_t *bs_public_key_bin = hex_string_to_bin((char *)bs_public_key);\n        const int address_resolved = DHT_bootstrap_from_address(dht, bs_address, enable_ipv6, htons(bs_port),\n                                     bs_public_key_bin);\n        free(bs_public_key_bin);\n\n        if (!address_resolved) {\n            write_log(LOG_LEVEL_WARNING, \"Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\\n\", i, NAME_ADDRESS, bs_address);\n            goto next;\n        }\n\n        write_log(LOG_LEVEL_INFO, \"Successfully added bootstrap node #%d: %s:%d %s\\n\", i, bs_address, bs_port, bs_public_key);\n\nnext:\n        // config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly\n        // though it's freed when the element is removed, so we free it right away in order to keep memory\n        // consumption minimal\n        config_setting_remove_elem(node_list, 0);\n        i++;\n    }\n\n    config_destroy(&cfg);\n\n    return 1;\n}\n"
  },
  {
    "path": "other/bootstrap_daemon/src/config_defaults.h",
    "content": "/* config_defaults.h\n *\n * Tox DHT bootstrap daemon.\n * Default config options for when they are missing in the config file.\n *\n *  Copyright (C) 2014-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef CONFIG_DEFAULTS_H\n#define CONFIG_DEFAULTS_H\n\n#include \"global.h\"\n\n#define DEFAULT_PID_FILE_PATH         \"tox-bootstrapd.pid\"\n#define DEFAULT_KEYS_FILE_PATH        \"tox-bootstrapd.keys\"\n#define DEFAULT_PORT                  33445\n#define DEFAULT_ENABLE_IPV6           1 // 1 - true, 0 - false\n#define DEFAULT_ENABLE_IPV4_FALLBACK  1 // 1 - true, 0 - false\n#define DEFAULT_ENABLE_LAN_DISCOVERY  1 // 1 - true, 0 - false\n#define DEFAULT_ENABLE_TCP_RELAY      1 // 1 - true, 0 - false\n#define DEFAULT_TCP_RELAY_PORTS       443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly\n#define DEFAULT_TCP_RELAY_PORTS_COUNT 3\n#define DEFAULT_ENABLE_MOTD           1 // 1 - true, 0 - false\n#define DEFAULT_MOTD                  DAEMON_NAME\n\n#endif // CONFIG_DEFAULTS_H\n"
  },
  {
    "path": "other/bootstrap_daemon/src/global.h",
    "content": "/* global.h\n *\n * Tox DHT bootstrap daemon.\n * Globally used defines.\n *\n *  Copyright (C) 2014-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef GLOBAL_H\n#define GLOBAL_H\n\n#define DAEMON_NAME \"tox-bootstrapd\"\n#define DAEMON_VERSION_NUMBER 2016010100UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day\n\n#define MIN_ALLOWED_PORT 1\n#define MAX_ALLOWED_PORT 65535\n\n#endif // GLOBAL_H\n"
  },
  {
    "path": "other/bootstrap_daemon/src/log.c",
    "content": "/* log.c\n *\n * Tox DHT bootstrap daemon.\n * Logging utility with support of multipel logging backends.\n *\n *  Copyright (C) 2015-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#include \"log.h\"\n\n#include \"global.h\"\n\n#include <syslog.h>\n\n#include <stdarg.h>\n#include <stdio.h>\n\nLOG_BACKEND current_backend = -1;\n\nbool open_log(LOG_BACKEND backend)\n{\n    if (current_backend != -1) {\n        return false;\n    }\n\n    if (backend == LOG_BACKEND_SYSLOG) {\n        openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);\n    }\n\n    current_backend = backend;\n\n    return true;\n}\n\nbool close_log()\n{\n    if (current_backend == -1) {\n        return false;\n    }\n\n    if (current_backend == LOG_BACKEND_SYSLOG) {\n        closelog();\n    }\n\n    current_backend = -1;\n\n    return true;\n}\n\nint level_syslog(LOG_LEVEL level)\n{\n    switch (level) {\n        case LOG_LEVEL_INFO:\n            return LOG_INFO;\n\n        case LOG_LEVEL_WARNING:\n            return LOG_WARNING;\n\n        case LOG_LEVEL_ERROR:\n            return LOG_ERR;\n    }\n\n    return LOG_INFO;\n}\n\nvoid log_syslog(LOG_LEVEL level, const char *format, va_list args)\n{\n    vsyslog(level_syslog(level), format, args);\n}\n\nFILE *level_stdout(LOG_LEVEL level)\n{\n    switch (level) {\n        case LOG_LEVEL_INFO:\n            return stdout;\n\n        case LOG_LEVEL_WARNING: // intentional fallthrough\n        case LOG_LEVEL_ERROR:\n            return stderr;\n    }\n\n    return stdout;\n}\n\nvoid log_stdout(LOG_LEVEL level, const char *format, va_list args)\n{\n    vfprintf(level_stdout(level), format, args);\n    fflush(level_stdout(level));\n}\n\nbool write_log(LOG_LEVEL level, const char *format, ...)\n{\n    va_list args;\n    va_start(args, format);\n\n    switch (current_backend) {\n        case LOG_BACKEND_SYSLOG:\n            log_syslog(level, format, args);\n            break;\n\n        case LOG_BACKEND_STDOUT:\n            log_stdout(level, format, args);\n            break;\n    }\n\n    va_end(args);\n\n    return current_backend != -1;\n}\n"
  },
  {
    "path": "other/bootstrap_daemon/src/log.h",
    "content": "/* log.h\n *\n * Tox DHT bootstrap daemon.\n * Logging utility with support of multipel logging backends.\n *\n *  Copyright (C) 2015-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef LOG_H\n#define LOG_H\n\n#include <stdbool.h>\n\ntypedef enum LOG_BACKEND {\n    LOG_BACKEND_SYSLOG,\n    LOG_BACKEND_STDOUT\n} LOG_BACKEND;\n\ntypedef enum LOG_LEVEL {\n    LOG_LEVEL_INFO,\n    LOG_LEVEL_WARNING,\n    LOG_LEVEL_ERROR\n} LOG_LEVEL;\n\n/**\n * Initializes logger.\n * @param backend Specifies which backend to use.\n * @return true on success, flase if log is already opened.\n */\nbool open_log(LOG_BACKEND backend);\n\n/**\n * Releases all used resources by the logger.\n * @return true on success, flase if log is already closed.\n */\nbool close_log();\n\n/**\n * Writes a message to the log.\n * @param level Log level to use.\n * @param format printf-like format string.\n * @param ... Zero or more arguments, similar to printf function.\n * @return true on success, flase if log is closed.\n */\nbool write_log(LOG_LEVEL level, const char *format, ...);\n\n\n#endif // LOG_H\n"
  },
  {
    "path": "other/bootstrap_daemon/src/tox-bootstrapd.c",
    "content": "/* tox-bootstrapd.c\n *\n * Tox DHT bootstrap daemon.\n * Main file.\n *\n *  Copyright (C) 2014-2016 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n// system provided\n#include <unistd.h>\n\n// C\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n\n// toxcore\n#include \"../../../toxcore/LAN_discovery.h\"\n#include \"../../../toxcore/onion_announce.h\"\n#include \"../../../toxcore/TCP_server.h\"\n#include \"../../../toxcore/util.h\"\n\n// misc\n#include \"../../bootstrap_node_packets.h\"\n\n#include \"command_line_arguments.h\"\n#include \"config.h\"\n#include \"global.h\"\n#include \"log.h\"\n\n\n#define SLEEP_MILLISECONDS(MS) usleep(1000*MS)\n\n// Uses the already existing key or creates one if it didn't exist\n//\n// retirns 1 on success\n//         0 on failure - no keys were read or stored\n\nint manage_keys(DHT *dht, char *keys_file_path)\n{\n    const uint32_t KEYS_SIZE = crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;\n    uint8_t keys[KEYS_SIZE];\n    FILE *keys_file;\n\n    // Check if file exits, proceed to open and load keys\n    keys_file = fopen(keys_file_path, \"r\");\n\n    if (keys_file != NULL) {\n        const size_t read_size = fread(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);\n\n        if (read_size != KEYS_SIZE) {\n            fclose(keys_file);\n            return 0;\n        }\n\n        memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);\n        memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);\n    } else {\n        // Otherwise save new keys\n        memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n        memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);\n\n        keys_file = fopen(keys_file_path, \"w\");\n\n        if (!keys_file)\n            return 0;\n\n        const size_t write_size = fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file);\n\n        if (write_size != KEYS_SIZE) {\n            fclose(keys_file);\n            return 0;\n        }\n    }\n\n    fclose(keys_file);\n\n    return 1;\n}\n\n// Prints public key\n\nvoid print_public_key(const uint8_t *public_key)\n{\n    char buffer[2 * crypto_box_PUBLICKEYBYTES + 1];\n    int index = 0;\n\n    size_t i;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {\n        index += sprintf(buffer + index, \"%02hhX\", public_key[i]);\n    }\n\n    write_log(LOG_LEVEL_INFO, \"Public Key: %s\\n\", buffer);\n\n    return;\n}\n\n// Demonizes the process, appending PID to the PID file and closing file descriptors based on log backend\n// Terminates the application if the daemonization fails.\n\nvoid daemonize(LOG_BACKEND log_backend, char *pid_file_path)\n{\n    // Check if the PID file exists\n    FILE *pid_file;\n\n    if ((pid_file = fopen(pid_file_path, \"r\"))) {\n        write_log(LOG_LEVEL_WARNING, \"Another instance of the daemon is already running, PID file %s exists.\\n\", pid_file_path);\n        fclose(pid_file);\n    }\n\n    // Open the PID file for writing\n    pid_file = fopen(pid_file_path, \"a+\");\n\n    if (pid_file == NULL) {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't open the PID file for writing: %s. Exiting.\\n\", pid_file_path);\n        exit(1);\n    }\n\n    // Fork off from the parent process\n    const pid_t pid = fork();\n\n    if (pid > 0) {\n        fprintf(pid_file, \"%d\", pid);\n        fclose(pid_file);\n        write_log(LOG_LEVEL_INFO, \"Forked successfully: PID: %d.\\n\", pid);\n        exit(0);\n    } else {\n        fclose(pid_file);\n    }\n\n    if (pid < 0) {\n        write_log(LOG_LEVEL_ERROR, \"Forking failed. Exiting.\\n\");\n        exit(1);\n    }\n\n    // Create a new SID for the child process\n    if (setsid() < 0) {\n        write_log(LOG_LEVEL_ERROR, \"SID creation failure. Exiting.\\n\");\n        exit(1);\n    }\n\n\n    // Change the current working directory\n    if ((chdir(\"/\")) < 0) {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't change working directory to '/'. Exiting.\\n\");\n        exit(1);\n    }\n\n    // Go quiet\n    if (log_backend != LOG_BACKEND_STDOUT) {\n        close(STDOUT_FILENO);\n        close(STDIN_FILENO);\n        close(STDERR_FILENO);\n    }\n}\n\nint main(int argc, char *argv[])\n{\n    umask(077);\n    char *cfg_file_path;\n    LOG_BACKEND log_backend;\n    bool run_in_foreground;\n\n    // choose backend for printing command line argument parsing output based on whether the daemon is being run from a terminal\n    log_backend = isatty(STDOUT_FILENO) ? LOG_BACKEND_STDOUT : LOG_BACKEND_SYSLOG;\n\n    open_log(log_backend);\n    handle_command_line_arguments(argc, argv, &cfg_file_path, &log_backend, &run_in_foreground);\n    close_log();\n\n    open_log(log_backend);\n\n    write_log(LOG_LEVEL_INFO, \"Running \\\"%s\\\" version %lu.\\n\", DAEMON_NAME, DAEMON_VERSION_NUMBER);\n\n    char *pid_file_path, *keys_file_path;\n    int port;\n    int enable_ipv6;\n    int enable_ipv4_fallback;\n    int enable_lan_discovery;\n    int enable_tcp_relay;\n    uint16_t *tcp_relay_ports;\n    int tcp_relay_port_count;\n    int enable_motd;\n    char *motd;\n\n    if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_ipv4_fallback,\n                           &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {\n        write_log(LOG_LEVEL_INFO, \"General config read successfully\\n\");\n    } else {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't read config file: %s. Exiting.\\n\", cfg_file_path);\n        return 1;\n    }\n\n    if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {\n        write_log(LOG_LEVEL_ERROR, \"Invalid port: %d, should be in [%d, %d]. Exiting.\\n\", port, MIN_ALLOWED_PORT,\n                  MAX_ALLOWED_PORT);\n        return 1;\n    }\n\n    if (!run_in_foreground) {\n        daemonize(log_backend, pid_file_path);\n    }\n\n    free(pid_file_path);\n\n    IP ip;\n    ip_init(&ip, enable_ipv6);\n\n    Networking_Core *net = new_networking(ip, port);\n\n    if (net == NULL) {\n        if (enable_ipv6 && enable_ipv4_fallback) {\n            write_log(LOG_LEVEL_WARNING, \"Couldn't initialize IPv6 networking. Falling back to using IPv4.\\n\");\n            enable_ipv6 = 0;\n            ip_init(&ip, enable_ipv6);\n            net = new_networking(ip, port);\n\n            if (net == NULL) {\n                write_log(LOG_LEVEL_ERROR, \"Couldn't fallback to IPv4. Exiting.\\n\");\n                return 1;\n            }\n        } else {\n            write_log(LOG_LEVEL_ERROR, \"Couldn't initialize networking. Exiting.\\n\");\n            return 1;\n        }\n    }\n\n    DHT *dht = new_DHT(net);\n\n    if (dht == NULL) {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't initialize Tox DHT instance. Exiting.\\n\");\n        return 1;\n    }\n\n    Onion *onion = new_onion(dht);\n    Onion_Announce *onion_a = new_onion_announce(dht);\n\n    if (!(onion && onion_a)) {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't initialize Tox Onion. Exiting.\\n\");\n        return 1;\n    }\n\n    if (enable_motd) {\n        if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t *)motd, strlen(motd) + 1) == 0) {\n            write_log(LOG_LEVEL_INFO, \"Set MOTD successfully.\\n\");\n        } else {\n            write_log(LOG_LEVEL_ERROR, \"Couldn't set MOTD: %s. Exiting.\\n\", motd);\n            return 1;\n        }\n\n        free(motd);\n    }\n\n    if (manage_keys(dht, keys_file_path)) {\n        write_log(LOG_LEVEL_INFO, \"Keys are managed successfully.\\n\");\n    } else {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't read/write: %s. Exiting.\\n\", keys_file_path);\n        return 1;\n    }\n\n    free(keys_file_path);\n\n    TCP_Server *tcp_server = NULL;\n\n    if (enable_tcp_relay) {\n        if (tcp_relay_port_count == 0) {\n            write_log(LOG_LEVEL_ERROR, \"No TCP relay ports read. Exiting.\\n\");\n            return 1;\n        }\n\n        tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_secret_key, onion);\n\n        // tcp_relay_port_count != 0 at this point\n        free(tcp_relay_ports);\n\n        if (tcp_server != NULL) {\n            write_log(LOG_LEVEL_INFO, \"Initialized Tox TCP server successfully.\\n\");\n        } else {\n            write_log(LOG_LEVEL_ERROR, \"Couldn't initialize Tox TCP server. Exiting.\\n\");\n            return 1;\n        }\n    }\n\n    if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {\n        write_log(LOG_LEVEL_INFO, \"List of bootstrap nodes read successfully.\\n\");\n    } else {\n        write_log(LOG_LEVEL_ERROR, \"Couldn't read list of bootstrap nodes in %s. Exiting.\\n\", cfg_file_path);\n        return 1;\n    }\n\n    print_public_key(dht->self_public_key);\n\n    uint64_t last_LANdiscovery = 0;\n    const uint16_t htons_port = htons(port);\n\n    int waiting_for_dht_connection = 1;\n\n    if (enable_lan_discovery) {\n        LANdiscovery_init(dht);\n        write_log(LOG_LEVEL_INFO, \"Initialized LAN discovery successfully.\\n\");\n    }\n\n    while (1) {\n        do_DHT(dht);\n\n        if (enable_lan_discovery && is_timeout(last_LANdiscovery, LAN_DISCOVERY_INTERVAL)) {\n            send_LANdiscovery(htons_port, dht);\n            last_LANdiscovery = unix_time();\n        }\n\n        if (enable_tcp_relay) {\n            do_TCP_server(tcp_server);\n        }\n\n        networking_poll(dht->net);\n\n        if (waiting_for_dht_connection && DHT_isconnected(dht)) {\n            write_log(LOG_LEVEL_INFO, \"Connected to another bootstrap node successfully.\\n\");\n            waiting_for_dht_connection = 0;\n        }\n\n        SLEEP_MILLISECONDS(30);\n    }\n\n    return 1;\n}\n"
  },
  {
    "path": "other/bootstrap_daemon/tox-bootstrapd.conf",
    "content": "// Tox DHT bootstrap daemon configuration file.\n\n// Listening port (UDP).\nport = 33445\n\n// A key file is like a password, so keep it where no one can read it.\n// If there is no key file, a new one will be generated.\n// The daemon should have permission to read/write it.\nkeys_file_path = \"/var/lib/tox-bootstrapd/keys\"\n\n// The PID file written to by the daemon.\n// Make sure that the user that daemon runs as has permissions to write to the\n// PID file.\npid_file_path = \"/var/run/tox-bootstrapd/tox-bootstrapd.pid\"\n\n// Enable IPv6.\nenable_ipv6 = true\n\n// Fallback to IPv4 in case IPv6 fails.\nenable_ipv4_fallback = true\n\n// Automatically bootstrap with nodes on local area network.\nenable_lan_discovery = true\n\nenable_tcp_relay = true\n\n// While Tox uses 33445 port by default, 443 (https) and 3389 (rdp) ports are very\n// common among nodes, so it's encouraged to keep them in place.\ntcp_relay_ports = [443, 3389, 33445]\n\n// Reply to MOTD (Message Of The Day) requests.\nenable_motd = true\n\n// Just a message that is sent when someone requests MOTD.\n// Put anything you want, but note that it will be trimmed to fit into 255 bytes.\nmotd = \"tox-bootstrapd\"\n\n// Any number of nodes the daemon will bootstrap itself off.\n//\n// Remember to replace the provided example with your own node list.\n// There is a maintained list of bootstrap nodes on Tox's wiki, if you need it\n// (https://wiki.tox.chat/doku.php?id=users:nodes).\n//\n// You may leave the list empty or remove \"bootstrap_nodes\" completely,\n// in both cases this will be interpreted as if you don't want to bootstrap\n// from anyone.\n//\n// address = any IPv4 or IPv6 address and also any US-ASCII domain name.\nbootstrap_nodes = (\n  { // Example Node 1 (IPv4)\n    address = \"127.0.0.1\"\n    port = 33445\n    public_key = \"728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854\"\n  },\n  { // Example Node 2 (IPv6)\n    address = \"::1/128\"\n    port = 33445\n    public_key = \"3E78BACF0F84235B30054B54898F56793E1DEF8BD46B1038B9D822E8460FAB67\"\n  },\n  { // Example Node 3 (US-ASCII domain name)\n    address = \"example.org\"\n    port = 33445\n    public_key = \"8CD5A9BF0A6CE358BA36F7A653F99FA6B258FF756E490F52C1F98CC420F78858\"\n  }\n)"
  },
  {
    "path": "other/bootstrap_daemon/tox-bootstrapd.service",
    "content": "[Unit]\nDescription=Tox DHT Bootstrap Daemon\nAfter=network.target\n\n[Service]\nType=forking\nRuntimeDirectory=tox-bootstrapd\nRuntimeDirectoryMode=750\nPIDFile=/var/run/tox-bootstrapd/tox-bootstrapd.pid\nWorkingDirectory=/var/lib/tox-bootstrapd\nExecStart=/usr/local/bin/tox-bootstrapd --config /etc/tox-bootstrapd.conf\nUser=tox-bootstrapd\nGroup=tox-bootstrapd\n#CapabilityBoundingSet=CAP_NET_BIND_SERVICE\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "other/bootstrap_daemon/tox-bootstrapd.sh",
    "content": "#! /bin/sh\n### BEGIN INIT INFO\n# Provides:          tox-bootstrapd\n# Required-Start:    $remote_fs $syslog\n# Required-Stop:     $remote_fs $syslog\n# Default-Start:     2 3 4 5\n# Default-Stop:      0 1 6\n# Short-Description: Starts the Tox DHT bootstrapping server daemon\n# Description:       Starts the Tox DHT bootstrapping server daemon\n### END INIT INFO\n\n# PATH should only include /usr/* if it runs after the mountnfs.sh script\nPATH=/sbin:/usr/sbin:/bin:/usr/bin\nDESC=\"Tox DHT bootstrap daemon\"\nNAME=tox-bootstrapd\nDAEMON=/usr/local/bin/$NAME\nCFGFILE=/etc/$NAME.conf\nDAEMON_ARGS=\"--config $CFGFILE\"\nPIDDIR=/var/run/$NAME\nPIDFILE=$PIDDIR/$NAME.pid\nSCRIPTNAME=/etc/init.d/$NAME\nUSER=tox-bootstrapd\nGROUP=tox-bootstrapd\n\n# Exit if the package is not installed\n[ -x \"$DAEMON\" ] || exit 0\n\n# Load the VERBOSE setting and other rcS variables\n. /lib/init/vars.sh\n\n# Define LSB log_* functions.\n# Depend on lsb-base (>= 3.2-14) to ensure that this file is present\n# and status_of_proc is working.\n. /lib/lsb/init-functions\n\n#\n# Function that starts the daemon/service\n#\ndo_start()\n{\n\t# Return\n\t#   0 if daemon has been started\n\t#   1 if daemon was already running\n\t#   2 if daemon could not be started\n\tif [ ! -d $PIDDIR ]\n\tthen\n\t\tmkdir $PIDDIR\n\tfi\n\tchown $USER:$GROUP $PIDDIR\n\tstart-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test --chuid $USER > /dev/null || return 1\n\tstart-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid $USER -- $DAEMON_ARGS || return 2\n}\n\n#\n# Function that stops the daemon/service\n#\ndo_stop()\n{\n\t# Return\n\t#   0 if daemon has been stopped\n\t#   1 if daemon was already stopped\n\t#   2 if daemon could not be stopped\n\t#   other if a failure occurred\n\tstart-stop-daemon --stop --quiet --retry 5 --pidfile $PIDFILE --name $NAME --chuid $USER\n\tRETVAL=\"$?\"\n\t[ \"$RETVAL\" = 2 ] && return 2\n\t# Many daemons don't delete their pidfiles when they exit.\n\trm -f $PIDFILE\n\treturn \"$RETVAL\"\n}\n\ncase \"$1\" in\n  start)\n\t[ \"$VERBOSE\" != no ] && log_daemon_msg \"Starting $DESC\" \"$NAME\"\n\tdo_start\n\tcase \"$?\" in\n\t\t0|1) [ \"$VERBOSE\" != no ] && log_end_msg 0 ;;\n\t\t2) [ \"$VERBOSE\" != no ] && log_end_msg 1 ;;\n\tesac\n\t;;\n  stop)\n\t[ \"$VERBOSE\" != no ] && log_daemon_msg \"Stopping $DESC\" \"$NAME\"\n\tdo_stop\n\tcase \"$?\" in\n\t\t0|1) [ \"$VERBOSE\" != no ] && log_end_msg 0 ;;\n\t\t2) [ \"$VERBOSE\" != no ] && log_end_msg 1 ;;\n\tesac\n\t;;\n  status)\n\tstatus_of_proc -p $PIDFILE \"$DAEMON\" \"$NAME\" && exit 0 || exit $?\n\t;;\n\n  restart)\n\tlog_daemon_msg \"Restarting $DESC\" \"$NAME\"\n\tdo_stop\n\tcase \"$?\" in\n\t  0|1)\n\t\tdo_start\n\t\tcase \"$?\" in\n\t\t\t0) log_end_msg 0 ;;\n\t\t\t1) log_end_msg 1 ;; # Old process is still running\n\t\t\t*) log_end_msg 1 ;; # Failed to start\n\t\tesac\n\t\t;;\n\t  *)\n\t\t# Failed to stop\n\t\tlog_end_msg 1\n\t\t;;\n\tesac\n\t;;\n  *)\n\techo \"Usage: $SCRIPTNAME {start|stop|status|restart}\" >&2\n\texit 3\n\t;;\nesac\nexit 0"
  },
  {
    "path": "other/bootstrap_node_packets.c",
    "content": "/* bootstrap_node_packets.c\n *\n * Special bootstrap node only packets.\n *\n * Include it in your bootstrap node and use: bootstrap_set_callbacks() to enable.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#include \"bootstrap_node_packets.h\"\n\n#define INFO_REQUEST_PACKET_LENGTH 78\n\nstatic uint32_t bootstrap_version;\nstatic uint8_t bootstrap_motd[MAX_MOTD_LENGTH];\nstatic uint16_t bootstrap_motd_length;\n\n/* To request this packet just send a packet of length INFO_REQUEST_PACKET_LENGTH\n * with the first byte being BOOTSTRAP_INFO_PACKET_ID\n */\nstatic int handle_info_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    if (length != INFO_REQUEST_PACKET_LENGTH)\n        return 1;\n\n    uint8_t data[1 + sizeof(bootstrap_version) + MAX_MOTD_LENGTH];\n    data[0] = BOOTSTRAP_INFO_PACKET_ID;\n    memcpy(data + 1, &bootstrap_version, sizeof(bootstrap_version));\n    uint16_t len = 1 + sizeof(bootstrap_version) + bootstrap_motd_length;\n    memcpy(data + 1 + sizeof(bootstrap_version), bootstrap_motd, bootstrap_motd_length);\n\n    if (sendpacket(object, source, data, len) == len)\n        return 0;\n\n    return 1;\n}\n\nint bootstrap_set_callbacks(Networking_Core *net, uint32_t version, uint8_t *motd, uint16_t motd_length)\n{\n    if (motd_length > MAX_MOTD_LENGTH)\n        return -1;\n\n    bootstrap_version = htonl(version);\n    memcpy(bootstrap_motd, motd, motd_length);\n    bootstrap_motd_length = motd_length;\n\n    networking_registerhandler(net, BOOTSTRAP_INFO_PACKET_ID, &handle_info_request, net);\n    return 0;\n}\n"
  },
  {
    "path": "other/bootstrap_node_packets.h",
    "content": "/* bootstrap_node_packets.h\n *\n * Special bootstrap node only packets.\n *\n * Include it in your bootstrap node and use: bootstrap_set_callbacks() to enable.\n *\n *  Copyright (C) 2015 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef BOOTSTRAP_NODE_PACKETS_H\n#define BOOTSTRAP_NODE_PACKETS_H\n\n#include \"../toxcore/network.h\"\n\n#define MAX_MOTD_LENGTH 256 /* I recommend you use a maximum of 96 bytes. The hard maximum is this though. */\n\nint bootstrap_set_callbacks(Networking_Core *net, uint32_t version, uint8_t *motd, uint16_t motd_length);\n\n#endif // BOOTSTRAP_NODE_PACKETS_H\n"
  },
  {
    "path": "other/fun/bootstrap_node_info.py",
    "content": "#!/usr/bin/env python\n\"\"\"\nCopyright (c) 2014 by nurupo <nurupo.contributions@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\"\"\"\n\nfrom socket import *\nimport sys\n\nif sys.version_info[0] == 2:\n    print(\"This script requires Python 3+ in order to run.\")\n    sys.exit(1)\n\ndef printHelp():\n    print(\"Usage: \" + sys.argv[0] + \" <ipv4|ipv6> <ip/hostname> <port>\")\n    print(\"  Example: \" + sys.argv[0] + \" ipv4 192.210.149.121 33445\")\n    print(\"  Example: \" + sys.argv[0] + \" ipv4 23.226.230.47 33445\")\n    print(\"  Example: \" + sys.argv[0] + \" ipv4 biribiri.org 33445\")\n    print(\"  Example: \" + sys.argv[0] + \" ipv4 cerberus.zodiaclabs.org 33445\")\n    print(\"  Example: \" + sys.argv[0] + \" ipv6 2604:180:1::3ded:b280 33445\")\n    print(\"\")\n    print(\"Return values:\")\n    print(\"  0 - received info reply from a node\")\n    print(\"  1 - incorrect command line arguments\")\n    print(\"  2 - didn't receive any reply from a node\")\n    print(\"  3 - received a malformed/unexpected reply\")\n\nif len(sys.argv) != 4:\n    printHelp()\n    sys.exit(1)\n\nprotocol = sys.argv[1]\nip = sys.argv[2]\nport = int(sys.argv[3])\n\nINFO_PACKET_ID = b\"\\xF0\"         # https://github.com/irungentoo/toxcore/blob/4940c4c62b6014d1f0586aa6aca7bf6e4ecfcf29/toxcore/network.h#L128\nINFO_REQUEST_PACKET_LENGTH = 78  # https://github.com/irungentoo/toxcore/blob/881b2d900d1998981fb6b9938ec66012d049635f/other/bootstrap_node_packets.c#L28\n# first byte is INFO_REQUEST_ID, other bytes don't matter as long as reqest's length matches INFO_REQUEST_LENGTH\nINFO_REQUEST_PACKET = INFO_PACKET_ID + ( b\"0\" * (INFO_REQUEST_PACKET_LENGTH - len(INFO_PACKET_ID)) )\n\nPACKET_ID_LENGTH = len(INFO_PACKET_ID)\nVERSION_LENGTH = 4    # https://github.com/irungentoo/toxcore/blob/881b2d900d1998981fb6b9938ec66012d049635f/other/bootstrap_node_packets.c#L44\nMAX_MOTD_LENGTH = 256 # https://github.com/irungentoo/toxcore/blob/881b2d900d1998981fb6b9938ec66012d049635f/other/bootstrap_node_packets.c#L26\n\nMAX_INFO_RESPONSE_PACKET_LENGTH = PACKET_ID_LENGTH + VERSION_LENGTH + MAX_MOTD_LENGTH\n\nSOCK_TIMEOUT_SECONDS = 1.0\n\nsock = None\n\nif protocol == \"ipv4\":\n    sock = socket(AF_INET, SOCK_DGRAM)\nelif protocol == \"ipv6\":\n    sock = socket(AF_INET6, SOCK_DGRAM)\nelse:\n    print(\"Invalid first argument\")\n    printHelp()\n    sys.exit(1)\n\nsock.sendto(INFO_REQUEST_PACKET, (ip, port))\n\nsock.settimeout(SOCK_TIMEOUT_SECONDS)\n\ntry:\n   data, addr = sock.recvfrom(MAX_INFO_RESPONSE_PACKET_LENGTH)\nexcept timeout:\n   print(\"The DHT bootstrap node didn't reply in \" + str(SOCK_TIMEOUT_SECONDS) + \" sec.\")\n   print(\"The likely reason for that is that the DHT bootstrap node is either offline or has no info set.\")\n   sys.exit(2)\n\npacketId = data[:PACKET_ID_LENGTH]\nif packetId != INFO_PACKET_ID:\n    print(\"Bad response, first byte should be\", INFO_PACKET_ID, \"but got\", packetId, \"(\", data, \")\")\n    print(\"Are you sure that you are pointing the script at a Tox DHT bootstrap node and that the script is up to date?\")\n    sys.exit(3)\n\nversion = int.from_bytes(data[PACKET_ID_LENGTH:PACKET_ID_LENGTH + VERSION_LENGTH], byteorder='big')\nmotd = data[PACKET_ID_LENGTH + VERSION_LENGTH:].decode(\"utf-8\")\nprint(\"Version: \" + str(version))\nprint(\"MOTD:    \" + motd)\nsys.exit(0)"
  },
  {
    "path": "other/fun/cracker.c",
    "content": "/* Public key cracker.\n *\n * Can be used to find public keys starting with specific hex (ABCD) for example.\n *\n * NOTE: There's probably a way to make this faster.\n *\n * Usage: ./cracker ABCDEF\n *\n * Will try to find a public key starting with: ABCDEF\n */\n\n#include \"../../testing/misc_tools.c\"\n#include <time.h>\n\n/* NaCl includes*/\n#include <crypto_scalarmult_curve25519.h>\n#include <randombytes.h>\n\n/* Sodium include*/\n//#include <sodium.h>\n\nvoid print_key(uint8_t *client_id)\n{\n    uint32_t j;\n\n    for (j = 0; j < 32; j++) {\n        printf(\"%02hhX\", client_id[j]);\n    }\n}\n\n\nint main(int argc, char *argv[])\n{\n    if (argc < 2) {\n        printf(\"usage: ./cracker public_key(or beginning of one in hex format)\\n\");\n        return 0;\n    }\n\n    long long unsigned int num_tries = 0;\n\n    uint32_t len = strlen(argv[1]) / 2;\n    unsigned char *key = hex_string_to_bin(argv[1]);\n    uint8_t pub_key[32], priv_key[32], c_key[32];\n\n    if (len > 32)\n        len = 32;\n\n    memcpy(c_key, key, len);\n    free(key);\n    randombytes(priv_key, 32);\n\n    while (1) {\n        crypto_scalarmult_curve25519_base(pub_key, priv_key);\n        uint32_t i;\n\n        if (memcmp(c_key, pub_key, len) == 0)\n            break;\n\n        for (i = 32; i != 0; --i) {\n            priv_key[i - 1] += 1;\n\n            if (priv_key[i - 1] != 0)\n                break;\n        }\n\n        ++num_tries;\n    }\n\n    printf(\"Public key:\\n\");\n    print_key(pub_key);\n    printf(\"\\nPrivate key:\\n\");\n    print_key(priv_key);\n    printf(\"\\n %llu keys tried\\n\", num_tries);\n    return 0;\n}\n"
  },
  {
    "path": "other/fun/make-funny-savefile.py",
    "content": "#!/usr/bin/python\n\n\"\"\"\nGenerate a new (and empty) save file with predefined keys. Used to play\nwith externally generated keys.\n\n(c) 2015 Alexandre Erwin Ittner\n\nDistributed under the GNU GPL v3 or later, WITHOUT ANY WARRANTY. See the\nfile \"COPYING\" for license information.\n\n\nUsage:\n\n  ./make-funny-savefile.py <public key> <private key> <user name> <out file>\n\n  The new user profile will be saved to <out file>.\n\n  The keys must be an hex-encoded valid key pair generated by any means\n  (eg. strkey.c); username may be anything. A random nospam value will be\n  generated.\n\n  Once the savefile is done, load it in your favorite client to get some\n  DHT nodes, set status and status messages, add friends, etc.\n\n\nExample (of course, do not try using this key for anything real):\n\n  ./make-funny-savefile.py 123411DC8B1A4760B648E0C7243B65F01069E4858F45C612CE1A6F673B603830 CC39440CFC063E4A95B7F2FB2580210558BE5C073AFC1C9604D431CCA3132238 \"Test user\" test.tox\n\n\n\"\"\"\n\n\nPUBLIC_KEY_LENGTH = 32\nPRIVATE_KEY_LENGTH = 32\n\n# Constants taken from messenger.c\nMESSENGER_STATE_COOKIE_GLOBAL       = 0x15ed1b1f\nMESSENGER_STATE_COOKIE_TYPE         = 0x01ce\nMESSENGER_STATE_TYPE_NOSPAMKEYS     = 1\nMESSENGER_STATE_TYPE_DHT            = 2\nMESSENGER_STATE_TYPE_FRIENDS        = 3\nMESSENGER_STATE_TYPE_NAME           = 4\nMESSENGER_STATE_TYPE_STATUSMESSAGE  = 5\nMESSENGER_STATE_TYPE_STATUS         = 6\nMESSENGER_STATE_TYPE_TCP_RELAY      = 10\nMESSENGER_STATE_TYPE_PATH_NODE      = 11\n\nSTATUS_MESSAGE = \"New user\".encode(\"utf-8\")\n\n\n\nimport sys\nimport struct\nimport os\n\ndef abort(msg):\n    print(msg)\n    exit(1)\n\n\n\nif len(sys.argv) != 5:\n    abort(\"Usage: %s <public key> <private key> <user name> <out file>\" % (sys.argv[0]))\n\ntry:\n    public_key = sys.argv[1].decode(\"hex\")\nexcept:\n    abort(\"Bad public key\")\n\ntry:\n    private_key = sys.argv[2].decode(\"hex\")\nexcept:\n    abort(\"Bad private key\")\n\nif len(public_key) != PUBLIC_KEY_LENGTH:\n    abort(\"Public key with wrong length\")\n\nif len(private_key) != PRIVATE_KEY_LENGTH:\n    abort(\"Private key with wrong length\")\n\nuser_name = sys.argv[3].encode(\"utf-8\")\n\nif len(user_name) > 32:\n    abort(\"User name too long (for this script, at least)\")\n\nout_file_name = sys.argv[4]\nnospam = os.urandom(4)\n\n\ndef make_subheader(h_type, h_length):\n    return (\n        struct.pack(\"<I\", h_length) +\n        struct.pack(\"<H\", h_type) +\n        struct.pack(\"<H\", MESSENGER_STATE_COOKIE_TYPE))\n\ndata = (\n    # Main header\n    struct.pack(\"<I\", 0) +\n    struct.pack(\"<I\", MESSENGER_STATE_COOKIE_GLOBAL) +\n\n    # Keys\n    make_subheader(MESSENGER_STATE_TYPE_NOSPAMKEYS,\n        len(nospam) + PUBLIC_KEY_LENGTH + PRIVATE_KEY_LENGTH) +\n    nospam + public_key + private_key +\n\n    # Name (not really needed, but helps)\n    make_subheader(MESSENGER_STATE_TYPE_NAME, len(user_name)) +\n    user_name +\n\n    # Status message (not really needed, but helps)\n    make_subheader(MESSENGER_STATE_TYPE_STATUSMESSAGE, len(STATUS_MESSAGE)) +\n    STATUS_MESSAGE\n)\n\n\ntry:\n    with open(out_file_name, \"wb\") as fp:\n        fp.write(data)\nexcept Exception as e:\n    abort(str(e))\n"
  },
  {
    "path": "other/fun/sign.c",
    "content": "/* Binary signer/checker using ed25519\n *\n * Compile with:\n *  gcc -o sign sign.c -lsodium\n *\n * Generate a keypair:\n *  ./sign g\n *\n * Sign a file:\n *  ./sign s PRIVATEKEY file.bin signedfile.bin\n *\n * Check a file:\n *\n * ./sign c PUBKEY signedfile.bin\n *\n * NOTE: The signature is appended to the end of the file.\n */\n#include <sodium.h>\n#include <string.h>\n#include \"../../testing/misc_tools.c\" // hex_string_to_bin\n\nint load_file(char *filename, char **result)\n{\n    int size = 0;\n    FILE *f = fopen(filename, \"rb\");\n\n    if (f == NULL) {\n        *result = NULL;\n        return -1; // -1 means file opening fail\n    }\n\n    fseek(f, 0, SEEK_END);\n    size = ftell(f);\n    fseek(f, 0, SEEK_SET);\n    *result = (char *)malloc(size + 1);\n\n    if (size != fread(*result, sizeof(char), size, f)) {\n        free(*result);\n        fclose(f);\n        return -2; // -2 means file reading fail\n    }\n\n    fclose(f);\n    (*result)[size] = 0;\n    return size;\n}\n\nint main(int argc, char *argv[])\n{\n    unsigned char pk[crypto_sign_ed25519_PUBLICKEYBYTES];\n    unsigned char sk[crypto_sign_ed25519_SECRETKEYBYTES];\n\n    if (argc == 2 && argv[1][0] == 'g') {\n        crypto_sign_ed25519_keypair(pk, sk);\n        printf(\"Public key:\\n\");\n        int i;\n\n        for (i = 0; i < crypto_sign_ed25519_PUBLICKEYBYTES; i++) {\n            printf(\"%02hhX\", pk[i]);\n        }\n\n        printf(\"\\nSecret key:\\n\");\n\n        for (i = 0; i < crypto_sign_ed25519_SECRETKEYBYTES; i++) {\n            printf(\"%02hhX\", sk[i]);\n        }\n\n        printf(\"\\n\");\n    }\n\n    if (argc == 5 && argv[1][0] == 's') {\n        unsigned char *secret_key = hex_string_to_bin(argv[2]);\n        char *data;\n        int size = load_file(argv[3], &data);\n\n        if (size < 0)\n            goto fail;\n\n        unsigned long long smlen;\n        char *sm = malloc(size + crypto_sign_ed25519_BYTES * 2);\n        crypto_sign_ed25519(sm, &smlen, data, size, secret_key);\n        free(secret_key);\n\n        if (smlen - size != crypto_sign_ed25519_BYTES)\n            goto fail;\n\n        FILE *f = fopen(argv[4], \"wb\");\n\n        if (f == NULL)\n            goto fail;\n\n        memcpy(sm + smlen, sm, crypto_sign_ed25519_BYTES); // Move signature from beginning to end of file.\n\n        if (fwrite(sm + (smlen - size), 1, smlen, f) != smlen)\n            goto fail;\n\n        fclose(f);\n        printf(\"Signed successfully.\\n\");\n    }\n\n    if (argc == 4 && argv[1][0] == 'c') {\n        unsigned char *public_key = hex_string_to_bin(argv[2]);\n        char *data;\n        int size = load_file(argv[3], &data);\n\n        if (size < 0)\n            goto fail;\n\n        char *signe = malloc(size + crypto_sign_ed25519_BYTES);\n        memcpy(signe, data + size - crypto_sign_ed25519_BYTES,\n               crypto_sign_ed25519_BYTES); // Move signature from end to beginning of file.\n        memcpy(signe + crypto_sign_ed25519_BYTES, data, size - crypto_sign_ed25519_BYTES);\n        unsigned long long smlen;\n        char *m = malloc(size);\n        unsigned long long mlen;\n\n        if (crypto_sign_ed25519_open(m, &mlen, signe, size, public_key) == -1) {\n            printf(\"Failed checking sig.\\n\");\n            goto fail;\n        }\n\n        printf(\"Checked successfully.\\n\");\n    }\n\n    return 0;\n\nfail:\n    printf(\"FAIL\\n\");\n    return 1;\n}\n"
  },
  {
    "path": "other/fun/strkey.c",
    "content": "/* strkey -- String in Public Key\n *\n * Generates Tox's key pairs, checking if a certain string is in the public key.\n *\n * Requires sodium or nacl library.\n *\n * There seem to be some problems with the code working on Windows -- it works\n * when built in debug mode with MinGW 4.8, but it doesn't work correctly when\n * built in release.\n *\n * Usage: strkey <offset> <string>\n *\n * Offset - an integer specifying exact byte offset position of the string you\n * are looking for within a public key. When offset is negative, the program\n * just looks for the desired string being somewhere, doesn't matter where, in\n * the public key.\n *\n * String - a hex string that you want to have in your public key. It must have\n * an even number of letters, since every two hexes map to a single byte of\n * the public key.\n *\n * Examples:\n *   strkey 0 0123\n *   Looks for a public key that begins with \"0123\".\n *\n *   strkey 1 0123\n *   Looks for a public key that has \"0123\" starting at its second byte, i.e. \"XX0123...\".\n *\n *   strkey 2 0123\n *   Looks for a public key that has \"0123\" starting at its third byte, i.e. \"XXXX0123...\".\n *   (each two hexes represent a single byte of a public key)\n *\n *   strkey -1 AF57CC\n *   Looks for a public key that contains \"AF57CC\", regardless of its position.\n *\n * To compile with gcc and sodium: gcc strkey.c -o strkey -lsodium\n*/\n\n#include <stdio.h>\n#include <string.h>\n\n#include <sodium.h>\n\n#define PRINT_TRIES_COUNT\n\nvoid print_key(unsigned char *key)\n{\n    size_t i;\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {\n        if (key[i] < 16) {\n            fprintf(stdout, \"0\");\n        }\n\n        fprintf(stdout, \"%hhX\", key[i]);\n    }\n}\n\nint main(int argc, char *argv[])\n{\n    unsigned char public_key[crypto_box_PUBLICKEYBYTES]; // null terminator\n    unsigned char secret_key[crypto_box_SECRETKEYBYTES];\n    int offset = 0;\n    size_t len;\n    unsigned char desired_bin[crypto_box_PUBLICKEYBYTES]; // null terminator\n\n    if (argc == 3) {\n        offset = atoi(argv[1]);\n        char *desired_hex = argv[2];\n        len = strlen(desired_hex);\n        if (len % 2 != 0) {\n            fprintf(stderr, \"Desired key should have an even number of letters\\n\");\n            exit(1);\n        }\n        size_t block_length = (offset < 0 ? 0 : offset) + len/2;\n        if (block_length > crypto_box_PUBLICKEYBYTES) {\n            fprintf(stderr, \"The given key with the given offset exceed public key's length\\n\");\n            exit(1);\n        }\n\n        // convert hex to bin\n        char *pos = desired_hex;\n        size_t i;\n        for (i = 0; i < len; pos += 2) {\n            sscanf(pos, \"%2hhx\", &desired_bin[i]);\n            ++i;\n        }\n    } else {\n        fprintf(stdout, \"Usage: executable <byte offset> <desired hex string with even number of letters>\\n\");\n        exit(1);\n    }\n\n    len /= 2;\n\n#ifdef PRINT_TRIES_COUNT\n    long long unsigned int tries = 0;\n#endif\n\n    if (offset < 0) {\n        int found = 0;\n        do {\n#ifdef PRINT_TRIES_COUNT\n            tries ++;\n#endif\n            crypto_box_keypair(public_key, secret_key);\n            int i;\n            for (i = 0; i <= crypto_box_PUBLICKEYBYTES - len; i ++) {\n                if (memcmp(public_key + i, desired_bin, len) == 0) {\n                    found = 1;\n                    break;\n                }\n            }\n        } while (!found);\n    } else {\n        unsigned char *p = public_key + offset;\n\n        do {\n#ifdef PRINT_TRIES_COUNT\n\t    tries ++;\n#endif\n            crypto_box_keypair(public_key, secret_key);\n        } while (memcmp(p, desired_bin, len) != 0);\n    }\n\n    fprintf(stdout, \"Public key:  \");\n    print_key(public_key);\n    fprintf(stdout, \"\\n\");\n\n    fprintf(stdout, \"Private key: \");\n    print_key(secret_key);\n    fprintf(stdout, \"\\n\");\n\n#ifdef PRINT_TRIES_COUNT\n\tfprintf(stdout, \"Found the key pair on %llu try.\\n\", tries);\n#endif\n\n    return 0;\n}\n"
  },
  {
    "path": "other/osx_build_script_toxcore.sh",
    "content": "#!/usr/bin/env bash\n# written by Lubo Diakov\n# hard coded toxcore directory, replace with other path or variable as needed\ncd ~/Downloads/toxcore\necho \"Now working in:\"`pwd`\n\n# must have working git binary, and have done git clone at least once before\ngit pull\necho \"If git pull responds: Already up-to-date. you can cancel the build\"\necho \"by typing anything except y or Y below\"\nread -p \"Continue with build? (enter y to continue): \" Last_Chance\n\n# blah blah\nif [[ $Last_Chance = [Yy] ]]; then echo \"Continuing!\";\nelse echo \"Aborted!\"; exit\nfi\nsleep 3\n\n# if libsodium is built with macports, link it from /opt/local/ to /usr/local\nif [ ! -L \"/usr/local/lib/libsodium.dylib\" ]; then\n  # Control will enter here if $DIRECTORY doesn't exist.\n   ln -s /opt/local/lib/libsodium.dylib /usr/local/lib/libsodium.dylib\nfi\necho \"The symlink /usr/local/lib/libsodium.dylib exists.\"\nsleep 3\n\n# replace ppc, i386 as needed.\n./configure CC=\"gcc -arch ppc -arch i386\" CXX=\"g++  -arch ppc -arch i386\" CPP=\"gcc -E\" CXXCPP=\"g++ -E\" \n\n# get rid of prior builds, start clean\nmake clean\nmake\necho \"\"\necho \"Sudo is required for make install only, all other steps run without it.\"\necho \"Please type your sudo password below for make install:\"\nsudo make install\n\nexit\n"
  },
  {
    "path": "super_donators/LittleVulpix",
    "content": "Thank you to all the tox-devs for the idea of a privacy-oriented chat protocol.\nThank you for seeing it through so that we have tox in its current state. It has ways to go, but it's already pretty good!\nIt is my dream that it will one day be as popular (or even more so) than the other protocols.\nThank you to everyone who is actively participating in maintaining and fixing things to make tox better today than it was yesterday!\nAnd finally a big thanks to the community that stayed together even through semi-tough times and united to fund the campaign!\n\nWorking filetransfers are my 'gift' to you all! Thanks to irungentoo for making it happen.\n\n\"I'm commander Shepard and this is my favourite chat protocol on the Internet.\"\n\n@LittleVulpix, 2015.\n"
  },
  {
    "path": "super_donators/grencez_tok5.c",
    "content": "/* Though it may look bleak at times,\n * this ring will stabilize to have one token,\n * and Tox will be the one true chat protocol!\n *  -- Alex P. Klinkhamer (grencez)\n */\n#include <unistd.h>\n#include <stdlib.h>\n#include <stdio.h>\nint main(int i, char** msg)\n{\n  int j, fd[4], xpd, xid;\n  if (--i<1)  return 1;\n  srand(getpid());\n  pipe(fd);\n  while (xid=rand()%5, --i>0) {\n    pipe(&fd[2]);\n    j = (0==fork() ? 0 : 1);\n    close(fd[j]);\n    fd[j] = fd[j+2];\n    close(fd[3-j]);\n    if (j==0)  break;\n  }\n#define SendSc()  write(fd[1], &xid, sizeof(xid))\n#define RecvPd()  read(fd[0], &xpd, sizeof(xpd))\n#define A(g,v)  if (g) {xid=v; puts(msg[i+1]); fflush(stdout); SendSc();}\n  SendSc();\n  while (RecvPd(), 1) {\n    sleep(1);\n    if (i==0) {\n      A( xpd==0 && xid==0 , 1 );\n      A( xpd==1 && xid<=1 , 2 );\n      A( xpd> 1 && xid> 1 , 0 );\n      continue;\n    }\n    A( xpd==0 && xid> 1 , xid/4 );\n    A( xpd==1 && xid!=1 , 1     );\n    A( xpd==2 && xid<=1 , 2+xid );\n    A( xpd>=3 && xid<=1 , 4     );\n  }\n  return 0;\n}\n"
  },
  {
    "path": "super_donators/sir@cmpwn.com",
    "content": "#!/bin/bash\n# Run ./sir@cmpwn.com\n# Arrow keys or wasd to move\n\nc=`tput cols`;L=`tput lines`\nlet x=$c/2;let y=$L/2;d=0;le=3;t=\"$y;$x\";i=0;j=0;S=0\nA(){ let i=($RANDOM%$c);let j=($RANDOM%$L);};A\nB(){ printf $*;};C(){ B \"\\x1B[$1\";};D(){ C \"$1H\";}\nF(){ D \"0;0\";C 2J;C \"?25h\";printf \"GAME OVER\\nSCORE: $S\\n\";exit;};trap F INT\nC ?25l;C 2J;da(){ D \"$j;$i\";echo \"$1\";}\nG() { for n in $t; do D \"$n\";echo \"$1\";done;}\nmt(){ t=`echo \"$t\"|cut -d' ' -f2-`;}\nsc(){ D \"0;0\";echo \"Score: $S\"; }\ngt() { t+=\" $y;$x\";};ct() { for n in $t; do [ \"$y;$x\" == \"$n\" ]&&F;done;}\nM() { case $d in 0)let y--;;1)let x--;;2)let y++;;3)let x++;;esac\nlet x%=$c;let y%=$L;ct;[ \"$y$x\" == \"$j$i\" ]&&{ let le++;A;let S++;}\nl=`tr -dc ' '<<<\"$t\"|wc -c`;gt;[ $l -gt $le ]&&mt;}\nky() { k=$1;read -sN1 -t 0.01 k1;read -sN1 -t 0.01 k2;read -sN1 -t 0.01 k3\nk+=${k1}${k2}${k3};case $k in w|$'\\e[A'|$'\\e0A')d=0;;a|$'\\e[D'|$'\\e0D')d=1;;\ns|$'\\e[B'|$'\\e0B')d=2;;d|$'\\e[C'|$'\\e0C')d=3;;esac;}\nwhile :;do da ' ';G ' ';M;da \"@\";G \"#\";sc;read -s -n 1 -t 0.1 k && ky \"$k\";done\n"
  },
  {
    "path": "testing/DHT_test.c",
    "content": "/* DHT test\n * A file with a main that runs our DHT for testing.\n *\n * Compile with: gcc -O2 -Wall -D VANILLA_NACL -o test ../core/Lossless_UDP.c ../core/network.c ../core/net_crypto.c ../core/Messenger.c ../nacl/build/${HOSTNAME%.*}/lib/amd64/{cpucycles.o,libnacl.a,randombytes.o} DHT_test.c\n *\n * Command line arguments are the ip, port and public key of a node.\n * EX: ./test 127.0.0.1 33445 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n *\n * The test will then ask you for the id (in hex format) of the friend you wish to add\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n//#include \"../core/network.h\"\n#include \"../toxcore/DHT.h\"\n#include \"../toxcore/friend_requests.h\"\n#include \"misc_tools.c\"\n\n#include <string.h>\n\n//Sleep function (x = milliseconds)\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n\n#define c_sleep(x) Sleep(1*x)\n\n#else\n#include <unistd.h>\n#include <arpa/inet.h>\n#define c_sleep(x) usleep(1000*x)\n\n#endif\n\n#define PORT 33445\n\nuint8_t zeroes_cid[crypto_box_PUBLICKEYBYTES];\n\nvoid print_client_id(uint8_t *public_key)\n{\n    uint32_t j;\n\n    for (j = 0; j < crypto_box_PUBLICKEYBYTES; j++) {\n        printf(\"%02hhX\", public_key[j]);\n    }\n}\n\nvoid print_hardening(Hardening *h)\n{\n    printf(\"Hardening:\\n\");\n    printf(\"routes_requests_ok: %hhu\\n\", h->routes_requests_ok);\n    printf(\"routes_requests_timestamp: %llu\\n\", (long long unsigned int)h->routes_requests_timestamp);\n    printf(\"routes_requests_pingedid: \");\n    print_client_id(h->routes_requests_pingedid);\n    printf(\"\\nsend_nodes_ok: %hhu\\n\", h->send_nodes_ok);\n    printf(\"send_nodes_timestamp: %llu\\n\", (long long unsigned int)h->send_nodes_timestamp);\n    printf(\"send_nodes_pingedid: \");\n    print_client_id(h->send_nodes_pingedid);\n    printf(\"\\ntesting_requests: %hhu\\n\", h->testing_requests);\n    printf(\"testing_timestamp: %llu\\n\", (long long unsigned int)h->testing_timestamp);\n    printf(\"testing_pingedid: \");\n    print_client_id(h->testing_pingedid);\n    printf(\"\\n\\n\");\n}\n\nvoid print_assoc(IPPTsPng *assoc, uint8_t ours)\n{\n    IP_Port *ipp = &assoc->ip_port;\n    printf(\"\\nIP: %s Port: %u\", ip_ntoa(&ipp->ip), ntohs(ipp->port));\n    printf(\"\\nTimestamp: %llu\", (long long unsigned int) assoc->timestamp);\n    printf(\"\\nLast pinged: %llu\\n\", (long long unsigned int) assoc->last_pinged);\n\n    ipp = &assoc->ret_ip_port;\n\n    if (ours)\n        printf(\"OUR IP: %s Port: %u\\n\", ip_ntoa(&ipp->ip), ntohs(ipp->port));\n    else\n        printf(\"RET IP: %s Port: %u\\n\", ip_ntoa(&ipp->ip), ntohs(ipp->port));\n\n    printf(\"Timestamp: %llu\\n\", (long long unsigned int) assoc->ret_timestamp);\n    print_hardening(&assoc->hardening);\n\n}\n\nvoid print_clientlist(DHT *dht)\n{\n    uint32_t i;\n    printf(\"___________________CLOSE________________________________\\n\");\n\n    for (i = 0; i < LCLIENT_LIST; i++) {\n        Client_data *client = &dht->close_clientlist[i];\n\n        if (public_key_cmp(client->public_key, zeroes_cid) == 0)\n            continue;\n\n        printf(\"ClientID: \");\n        print_client_id(client->public_key);\n\n        print_assoc(&client->assoc4, 1);\n        print_assoc(&client->assoc6, 1);\n    }\n}\n\nvoid print_friendlist(DHT *dht)\n{\n    uint32_t i, k;\n    IP_Port p_ip;\n    printf(\"_________________FRIENDS__________________________________\\n\");\n\n    for (k = 0; k < dht->num_friends; k++) {\n        printf(\"FRIEND %u\\n\", k);\n        printf(\"ID: \");\n\n        print_client_id(dht->friends_list[k].public_key);\n\n        int friendok = DHT_getfriendip(dht, dht->friends_list[k].public_key, &p_ip);\n        printf(\"\\nIP: %s:%u (%d)\", ip_ntoa(&p_ip.ip), ntohs(p_ip.port), friendok);\n\n        printf(\"\\nCLIENTS IN LIST:\\n\\n\");\n\n        for (i = 0; i < MAX_FRIEND_CLIENTS; i++) {\n            Client_data *client = &dht->friends_list[k].client_list[i];\n\n            if (public_key_cmp(client->public_key, zeroes_cid) == 0)\n                continue;\n\n            printf(\"ClientID: \");\n            print_client_id(client->public_key);\n\n            print_assoc(&client->assoc4, 0);\n            print_assoc(&client->assoc6, 0);\n        }\n    }\n}\n\nvoid printpacket(uint8_t *data, uint32_t length, IP_Port ip_port)\n{\n    uint32_t i;\n    printf(\"UNHANDLED PACKET RECEIVED\\nLENGTH:%u\\nCONTENTS:\\n\", length);\n    printf(\"--------------------BEGIN-----------------------------\\n\");\n\n    for (i = 0; i < length; i++) {\n        if (data[i] < 16)\n            printf(\"0\");\n\n        printf(\"%hhX\", data[i]);\n    }\n\n    printf(\"\\n--------------------END-----------------------------\\n\\n\\n\");\n}\n\nint main(int argc, char *argv[])\n{\n    if (argc < 4) {\n        printf(\"Usage: %s [--ipv4|--ipv6] ip port public_key\\n\", argv[0]);\n        exit(0);\n    }\n\n    /* let user override default by cmdline */\n    uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    //memcpy(self_client_id, \"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\", 32);\n    /* initialize networking */\n    /* bind to ip 0.0.0.0:PORT */\n    IP ip;\n    ip_init(&ip, ipv6enabled);\n\n    DHT *dht = new_DHT(new_networking(ip, PORT));\n    printf(\"OUR ID: \");\n    uint32_t i;\n\n    for (i = 0; i < 32; i++) {\n        if (dht->self_public_key[i] < 16)\n            printf(\"0\");\n\n        printf(\"%hhX\", dht->self_public_key[i]);\n    }\n\n    char temp_id[128];\n    printf(\"\\nEnter the public_key of the friend you wish to add (32 bytes HEX format):\\n\");\n\n    if (!fgets(temp_id, sizeof(temp_id), stdin))\n        exit(0);\n\n    if ((strlen(temp_id) > 0) && (temp_id[strlen(temp_id) - 1] == '\\n'))\n        temp_id[strlen(temp_id) - 1] = '\\0';\n\n    uint8_t *bin_id = hex_string_to_bin(temp_id);\n    DHT_addfriend(dht, bin_id, 0, 0, 0, 0);\n    free(bin_id);\n\n    perror(\"Initialization\");\n\n    uint16_t port = htons(atoi(argv[argvoffset + 2]));\n    unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);\n    int res = DHT_bootstrap_from_address(dht, argv[argvoffset + 1], ipv6enabled, port, binary_string);\n    free(binary_string);\n\n    if (!res) {\n        printf(\"Failed to convert \\\"%s\\\" into an IP address. Exiting...\\n\", argv[argvoffset + 1]);\n        return 1;\n    }\n\n    /*\n        IP_Port ip_port;\n        uint8_t data[MAX_UDP_PACKET_SIZE];\n        uint32_t length;\n    */\n\n    while (1) {\n\n        do_DHT(dht);\n\n        /* slvrTODO:\n                while(receivepacket(&ip_port, data, &length) != -1) {\n                    if(DHT_handlepacket(data, length, ip_port) && friendreq_handlepacket(data, length, ip_port)) {\n                        //unhandled packet\n                        printpacket(data, length, ip_port);\n                    } else {\n                        printf(\"Received handled packet with length: %u\\n\", length);\n                    }\n                }\n        */\n        networking_poll(dht->net);\n\n        print_clientlist(dht);\n        print_friendlist(dht);\n        c_sleep(300);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "testing/Makefile.inc",
    "content": "if BUILD_NTOX\n\nbin_PROGRAMS += nTox\n\nnTox_SOURCES =          ../testing/nTox.h \\\n                        ../testing/nTox.c\n\nnTox_CFLAGS =           $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS) \\\n                        $(NCURSES_CFLAGS)\n\nnTox_LDADD =            $(LIBSODIUM_LDFLAGS) \\\n                        $(NAC_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        $(NCURSES_LIBS) \\\n                        $(WINSOCK2_LIBS)\nendif\n\n\nif BUILD_TESTING\n\nnoinst_PROGRAMS +=      DHT_test \\\n                        Messenger_test \\\n                        dns3_test\n\nDHT_test_SOURCES =      ../testing/DHT_test.c\n\nDHT_test_CFLAGS =       $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\nDHT_test_LDADD =        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\n\nMessenger_test_SOURCES = \\\n                        ../testing/Messenger_test.c\n\nMessenger_test_CFLAGS = $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\nMessenger_test_LDADD =  $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\n\n\ndns3_test_SOURCES = \\\n                        ../testing/dns3_test.c\n\ndns3_test_CFLAGS = \\\n                        $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\ndns3_test_LDADD = \\\n                        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxdns.la \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\nif !WIN32\n\nnoinst_PROGRAMS +=      tox_sync\n\ntox_sync_SOURCES =      ../testing/tox_sync.c\n\ntox_sync_CFLAGS =       $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\ntox_sync_LDADD =        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS)\n\n\nnoinst_PROGRAMS +=      tox_shell\n\ntox_shell_SOURCES =      ../testing/tox_shell.c\n\ntox_shell_CFLAGS =       $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\ntox_shell_LDADD =        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS) \\\n                        -lutil\n\n\nnoinst_PROGRAMS +=      irc_syncbot\n\nirc_syncbot_SOURCES =   ../testing/irc_syncbot.c\n\nirc_syncbot_CFLAGS =    $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS)\n\nirc_syncbot_LDADD =    $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        libtoxcore.la \\\n                        $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NACL_LIBS)\nendif\n\nEXTRA_DIST += \t\t\t$(top_srcdir)/testing/misc_tools.c\n\nendif\n"
  },
  {
    "path": "testing/Messenger_test.c",
    "content": "/* Messenger test\n *\n * This program adds a friend and accepts all friend requests with the proper message.\n *\n * It tries sending a message to the added friend.\n *\n * If it receives a message from a friend it replies back.\n *\n *\n * This is how I compile it: gcc -O2 -Wall -D VANILLA_NACL -o test ../core/Lossless_UDP.c ../core/network.c ../core/net_crypto.c ../core/Messenger.c ../core/DHT.c ../nacl/build/${HOSTNAME%.*}/lib/amd64/{cpucycles.o,libnacl.a,randombytes.o} Messenger_test.c\n *\n *\n * Command line arguments are the ip, port and public_key of a node (for bootstrapping).\n *\n * EX: ./test 127.0.0.1 33445 CDCFD319CE3460824B33BE58FD86B8941C9585181D8FBD7C79C5721D7C2E9F7C\n *\n * Or the argument can be the path to the save file.\n *\n * EX: ./test Save.bak\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/Messenger.h\"\n#include \"misc_tools.c\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n\n#define c_sleep(x) Sleep(1*x)\n\n#else\n#include <unistd.h>\n#include <arpa/inet.h>\n#define c_sleep(x) usleep(1000*x)\n#define PORT 33445\n\n#endif\n\nvoid print_message(Messenger *m, uint32_t friendnumber, unsigned int type, const uint8_t *string, size_t length,\n                   void *userdata)\n{\n    printf(\"Message with length %lu received from %u: %s \\n\", length, friendnumber, string);\n    m_send_message_generic(m, friendnumber, type, (uint8_t *)\"Test1\", 6, 0);\n}\n\n/* FIXME needed as print_request has to match the interface expected by\n * networking_requesthandler and so cannot take a Messenger * */\nstatic Messenger *m;\n\nvoid print_request(Messenger *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    printf(\"Friend request received from: \\n\");\n    printf(\"ClientID: \");\n    uint32_t j;\n\n    for (j = 0; j < 32; j++) {\n        if (public_key[j] < 16)\n            printf(\"0\");\n\n        printf(\"%hhX\", public_key[j]);\n    }\n\n    printf(\"\\nOf length: %lu with data: %s \\n\", length, data);\n\n    if (length != sizeof(\"Install Gentoo\")) {\n        return;\n    }\n\n    if (memcmp(data , \"Install Gentoo\", sizeof(\"Install Gentoo\")) == 0 )\n        //if the request contained the message of peace the person is obviously a friend so we add him.\n    {\n        printf(\"Friend request accepted.\\n\");\n        m_addfriend_norequest(m, public_key);\n    }\n}\n\nint main(int argc, char *argv[])\n{\n    /* let user override default by cmdline */\n    uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    /* with optional --ipvx, now it can be 1-4 arguments... */\n    if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) {\n        printf(\"Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\\n\", argv[0]);\n        printf(\"or\\n\");\n        printf(\"       %s [--ipv4|--ipv6] Save.bak (to read Save.bak as state file)\\n\", argv[0]);\n        exit(0);\n    }\n\n    Messenger_Options options = {0};\n    options.ipv6enabled = ipv6enabled;\n    m = new_messenger(&options, 0);\n\n    if ( !m ) {\n        fputs(\"Failed to allocate messenger datastructure\\n\", stderr);\n        exit(0);\n    }\n\n    if (argc == argvoffset + 4) {\n        uint16_t port = htons(atoi(argv[argvoffset + 2]));\n        uint8_t *bootstrap_key = hex_string_to_bin(argv[argvoffset + 3]);\n        int res = DHT_bootstrap_from_address(m->dht, argv[argvoffset + 1],\n                                             ipv6enabled, port, bootstrap_key);\n        free(bootstrap_key);\n\n        if (!res) {\n            printf(\"Failed to convert \\\"%s\\\" into an IP address. Exiting...\\n\", argv[argvoffset + 1]);\n            exit(1);\n        }\n    } else {\n        FILE *file = fopen(argv[argvoffset + 1], \"rb\");\n\n        if ( file == NULL ) {\n            printf(\"Failed to open \\\"%s\\\" - does it exist?\\n\", argv[argvoffset + 1]);\n            return 1;\n        }\n\n        int read;\n        uint8_t buffer[128000];\n        read = fread(buffer, 1, 128000, file);\n        printf(\"Messenger loaded: %i\\n\", messenger_load(m, buffer, read));\n        fclose(file);\n\n    }\n\n    m_callback_friendrequest(m, print_request, NULL);\n    m_callback_friendmessage(m, print_message, NULL);\n\n    printf(\"OUR ID: \");\n    uint32_t i;\n    uint8_t address[FRIEND_ADDRESS_SIZE];\n    getaddress(m, address);\n\n    for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) {\n        if (address[i] < 16)\n            printf(\"0\");\n\n        printf(\"%hhX\", address[i]);\n    }\n\n    setname(m, (uint8_t *)\"Anon\", 5);\n\n    char temp_hex_id[128];\n    printf(\"\\nEnter the address of the friend you wish to add (38 bytes HEX format):\\n\");\n\n    if (!fgets(temp_hex_id, sizeof(temp_hex_id), stdin))\n        exit(0);\n\n    if ((strlen(temp_hex_id) > 0) && (temp_hex_id[strlen(temp_hex_id) - 1] == '\\n'))\n        temp_hex_id[strlen(temp_hex_id) - 1] = '\\0';\n\n\n    uint8_t *bin_id = hex_string_to_bin(temp_hex_id);\n    int num = m_addfriend(m, bin_id, (uint8_t *)\"Install Gentoo\", sizeof(\"Install Gentoo\"));\n    free(bin_id);\n\n    perror(\"Initialization\");\n\n    while (1) {\n        uint8_t name[128];\n        getname(m, num, name);\n        printf(\"%s\\n\", name);\n\n        m_send_message_generic(m, num, MESSAGE_NORMAL, (uint8_t *)\"Test\", 5, 0);\n        do_messenger(m);\n        c_sleep(30);\n        FILE *file = fopen(\"Save.bak\", \"wb\");\n\n        if ( file == NULL ) {\n            return 1;\n        }\n\n        uint8_t *buffer = malloc(messenger_size(m));\n        messenger_save(m, buffer);\n        size_t write_result = fwrite(buffer, 1, messenger_size(m), file);\n\n        if (write_result < messenger_size(m)) {\n            return 1;\n        }\n\n        free(buffer);\n        fclose(file);\n    }\n\n    kill_messenger(m);\n}\n"
  },
  {
    "path": "testing/av_test.c",
    "content": "/**  av_test.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n *   Compile with (Linux only; in newly created directory toxcore/dir_name):\n *   gcc -o av_test ../toxav/av_test.c ../build/.libs/libtox*.a -lopencv_core \\\n *   -lopencv_highgui -lopencv_imgproc -lsndfile -pthread -lvpx -lopus -lsodium -lportaudio\n */\n\n\n#include \"../toxav/toxav.h\"\n#include \"../toxcore/tox.h\"\n#include \"../toxcore/util.h\"\n#include \"../toxcore/network.h\" /* current_time_monotonic() */\n\n/* Playing audio data */\n#include <portaudio.h>\n/* Reading audio */\n#include <sndfile.h>\n\n/* Reading and Displaying video data */\n#include <opencv/cv.h>\n#include <opencv/highgui.h>\n#include <opencv/cvwimage.h>\n\n#include <sys/stat.h>\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n#include <string.h>\n#include <errno.h>\n#include <unistd.h>\n\n#define c_sleep(x) usleep(1000*x)\n\n\n#define CLIP(X) ((X) > 255 ? 255 : (X) < 0 ? 0 : X)\n\n// RGB -> YUV\n#define RGB2Y(R, G, B) CLIP((( 66 * (R) + 129 * (G) +  25 * (B) + 128) >> 8) +  16)\n#define RGB2U(R, G, B) CLIP(((-38 * (R) -  74 * (G) + 112 * (B) + 128) >> 8) + 128)\n#define RGB2V(R, G, B) CLIP(((112 * (R) -  94 * (G) -  18 * (B) + 128) >> 8) + 128)\n\n// YUV -> RGB\n#define C(Y) ((Y) - 16  )\n#define D(U) ((U) - 128 )\n#define E(V) ((V) - 128 )\n\n#define YUV2R(Y, U, V) CLIP((298 * C(Y)              + 409 * E(V) + 128) >> 8)\n#define YUV2G(Y, U, V) CLIP((298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8)\n#define YUV2B(Y, U, V) CLIP((298 * C(Y) + 516 * D(U)              + 128) >> 8)\n\n\n#define TEST_TRANSFER_A 0\n#define TEST_TRANSFER_V 1\n\n\ntypedef struct {\n    bool incoming;\n    uint32_t state;\n    pthread_mutex_t arb_mutex[1];\n    RingBuffer *arb; /* Audio ring buffer */\n\n} CallControl;\n\nstruct toxav_thread_data {\n    ToxAV  *AliceAV;\n    ToxAV  *BobAV;\n    int32_t sig;\n};\n\nconst char *vdout = \"AV Test\"; /* Video output */\nPaStream *adout = NULL; /* Audio output */\n\ntypedef struct {\n    uint16_t size;\n    int16_t data[];\n} frame;\n\nvoid *pa_write_thread (void *d)\n{\n    /* The purpose of this thread is to make sure Pa_WriteStream will not block\n     * toxav_iterate thread\n     */\n    CallControl *cc = d;\n\n    while (Pa_IsStreamActive(adout)) {\n        frame *f;\n        pthread_mutex_lock(cc->arb_mutex);\n\n        if (rb_read(cc->arb, (void **)&f)) {\n            pthread_mutex_unlock(cc->arb_mutex);\n            Pa_WriteStream(adout, f->data, f->size);\n            free(f);\n        } else {\n            pthread_mutex_unlock(cc->arb_mutex);\n            c_sleep(10);\n        }\n    }\n}\n\n/**\n * Callbacks\n */\nvoid t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)\n{\n    printf(\"Handling CALL callback\\n\");\n    ((CallControl *)user_data)->incoming = true;\n}\nvoid t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)\n{\n    printf(\"Handling CALL STATE callback: %d\\n\", state);\n    ((CallControl *)user_data)->state = state;\n}\nvoid t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,\n                                    uint16_t width, uint16_t height,\n                                    uint8_t const *y, uint8_t const *u, uint8_t const *v,\n                                    int32_t ystride, int32_t ustride, int32_t vstride,\n                                    void *user_data)\n{\n    ystride = abs(ystride);\n    ustride = abs(ustride);\n    vstride = abs(vstride);\n\n    uint16_t *img_data = malloc(height * width * 6);\n\n    unsigned long int i, j;\n\n    for (i = 0; i < height; ++i) {\n        for (j = 0; j < width; ++j) {\n            uint8_t *point = (uint8_t *) img_data + 3 * ((i * width) + j);\n            int yx = y[(i * ystride) + j];\n            int ux = u[((i / 2) * ustride) + (j / 2)];\n            int vx = v[((i / 2) * vstride) + (j / 2)];\n\n            point[0] = YUV2R(yx, ux, vx);\n            point[1] = YUV2G(yx, ux, vx);\n            point[2] = YUV2B(yx, ux, vx);\n        }\n    }\n\n\n    CvMat mat = cvMat(height, width, CV_8UC3, img_data);\n\n    CvSize sz = {.height = height, .width = width};\n\n    IplImage *header = cvCreateImageHeader(sz, 1, 3);\n    IplImage *img = cvGetImage(&mat, header);\n    cvShowImage(vdout, img);\n    free(img_data);\n}\nvoid t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,\n                                    int16_t const *pcm,\n                                    size_t sample_count,\n                                    uint8_t channels,\n                                    uint32_t sampling_rate,\n                                    void *user_data)\n{\n    CallControl *cc = user_data;\n    frame *f = malloc(sizeof(uint16_t) + sample_count * sizeof(int16_t) * channels);\n    memcpy(f->data, pcm, sample_count * sizeof(int16_t) * channels);\n    f->size = sample_count;\n\n    pthread_mutex_lock(cc->arb_mutex);\n    free(rb_write(cc->arb, f));\n    pthread_mutex_unlock(cc->arb_mutex);\n}\nvoid t_toxav_bit_rate_status_cb(ToxAV *av, uint32_t friend_number,\n                                uint32_t audio_bit_rate, uint32_t video_bit_rate,\n                                void *user_data)\n{\n    printf (\"Suggested bit rates: audio: %d video: %d\\n\", audio_bit_rate, video_bit_rate);\n}\nvoid t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    if (length == 7 && memcmp(\"gentoo\", data, 7) == 0) {\n        assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);\n    }\n}\n\n/**\n */\nvoid initialize_tox(Tox **bootstrap, ToxAV **AliceAV, CallControl *AliceCC, ToxAV **BobAV, CallControl *BobCC)\n{\n    Tox *Alice;\n    Tox *Bob;\n\n    struct Tox_Options opts;\n    tox_options_default(&opts);\n\n    opts.end_port = 0;\n    opts.ipv6_enabled = false;\n\n    {\n        TOX_ERR_NEW error;\n\n        opts.start_port = 33445;\n        *bootstrap = tox_new(&opts, &error);\n        assert(error == TOX_ERR_NEW_OK);\n\n        opts.start_port = 33455;\n        Alice = tox_new(&opts, &error);\n        assert(error == TOX_ERR_NEW_OK);\n\n        opts.start_port = 33465;\n        Bob = tox_new(&opts, &error);\n        assert(error == TOX_ERR_NEW_OK);\n    }\n\n    printf(\"Created 3 instances of Tox\\n\");\n    printf(\"Preparing network...\\n\");\n    long long unsigned int cur_time = time(NULL);\n\n    uint32_t to_compare = 974536;\n    uint8_t address[TOX_ADDRESS_SIZE];\n\n    tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);\n    tox_self_get_address(Alice, address);\n\n\n    assert(tox_friend_add(Bob, address, (uint8_t *)\"gentoo\", 7, NULL) != (uint32_t) ~0);\n\n    uint8_t off = 1;\n\n    while (1) {\n        tox_iterate(*bootstrap);\n        tox_iterate(Alice);\n        tox_iterate(Bob);\n\n        if (tox_self_get_connection_status(*bootstrap) &&\n                tox_self_get_connection_status(Alice) &&\n                tox_self_get_connection_status(Bob) && off) {\n            printf(\"Toxes are online, took %llu seconds\\n\", time(NULL) - cur_time);\n            off = 0;\n        }\n\n        if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&\n                tox_friend_get_connection_status(Bob, 0, NULL) == TOX_CONNECTION_UDP)\n            break;\n\n        c_sleep(20);\n    }\n\n\n    TOXAV_ERR_NEW rc;\n    *AliceAV = toxav_new(Alice, &rc);\n    assert(rc == TOXAV_ERR_NEW_OK);\n\n    *BobAV = toxav_new(Bob, &rc);\n    assert(rc == TOXAV_ERR_NEW_OK);\n\n\n    /* Alice */\n    toxav_callback_call(*AliceAV, t_toxav_call_cb, AliceCC);\n    toxav_callback_call_state(*AliceAV, t_toxav_call_state_cb, AliceCC);\n    toxav_callback_bit_rate_status(*AliceAV, t_toxav_bit_rate_status_cb, AliceCC);\n    toxav_callback_video_receive_frame(*AliceAV, t_toxav_receive_video_frame_cb, AliceCC);\n    toxav_callback_audio_receive_frame(*AliceAV, t_toxav_receive_audio_frame_cb, AliceCC);\n\n    /* Bob */\n    toxav_callback_call(*BobAV, t_toxav_call_cb, BobCC);\n    toxav_callback_call_state(*BobAV, t_toxav_call_state_cb, BobCC);\n    toxav_callback_bit_rate_status(*BobAV, t_toxav_bit_rate_status_cb, BobCC);\n    toxav_callback_video_receive_frame(*BobAV, t_toxav_receive_video_frame_cb, BobCC);\n    toxav_callback_audio_receive_frame(*BobAV, t_toxav_receive_audio_frame_cb, BobCC);\n\n\n    printf(\"Created 2 instances of ToxAV\\n\");\n    printf(\"All set after %llu seconds!\\n\", time(NULL) - cur_time);\n}\nint iterate_tox(Tox *bootstrap, ToxAV *AliceAV, ToxAV *BobAV)\n{\n    tox_iterate(bootstrap);\n    tox_iterate(toxav_get_tox(AliceAV));\n    tox_iterate(toxav_get_tox(BobAV));\n\n    return MIN(tox_iteration_interval(toxav_get_tox(AliceAV)), tox_iteration_interval(toxav_get_tox(BobAV)));\n}\nvoid *iterate_toxav (void *data)\n{\n    struct toxav_thread_data *data_cast = data;\n#if defined TEST_TRANSFER_V && TEST_TRANSFER_V == 1\n    cvNamedWindow(vdout, CV_WINDOW_AUTOSIZE);\n#endif\n\n    while (data_cast->sig == 0) {\n        toxav_iterate(data_cast->AliceAV);\n        toxav_iterate(data_cast->BobAV);\n        int rc = MIN(toxav_iteration_interval(data_cast->AliceAV), toxav_iteration_interval(data_cast->BobAV));\n\n        printf(\"\\rIteration interval: %d            \", rc);\n        fflush(stdout);\n\n#if defined TEST_TRANSFER_V && TEST_TRANSFER_V == 1\n\n        if (!rc)\n            rc = 1;\n\n        cvWaitKey(rc);\n#else\n        c_sleep(rc);\n#endif\n    }\n\n    data_cast->sig = 1;\n\n#if defined TEST_TRANSFER_V && TEST_TRANSFER_V == 1\n    cvDestroyWindow(vdout);\n#endif\n\n    pthread_exit(NULL);\n}\n\nint send_opencv_img(ToxAV *av, uint32_t friend_number, const IplImage *img)\n{\n    int32_t strides[3] = { 1280, 640, 640 };\n    uint8_t *planes[3] = {\n        malloc(img->height * img->width),\n        malloc(img->height * img->width / 4),\n        malloc(img->height * img->width / 4),\n    };\n\n    int x_chroma_shift = 1;\n    int y_chroma_shift = 1;\n\n    int x, y;\n\n    for (y = 0; y < img->height; ++y) {\n        for (x = 0; x < img->width; ++x) {\n            uint8_t r = img->imageData[(x + y * img->width) * 3 + 0];\n            uint8_t g = img->imageData[(x + y * img->width) * 3 + 1];\n            uint8_t b = img->imageData[(x + y * img->width) * 3 + 2];\n\n            planes[0][x + y * strides[0]] = RGB2Y(r, g, b);\n\n            if (!(x % (1 << x_chroma_shift)) && !(y % (1 << y_chroma_shift))) {\n                const int i = x / (1 << x_chroma_shift);\n                const int j = y / (1 << y_chroma_shift);\n                planes[1][i + j * strides[1]] = RGB2U(r, g, b);\n                planes[2][i + j * strides[2]] = RGB2V(r, g, b);\n            }\n        }\n    }\n\n    int rc = toxav_video_send_frame(av, friend_number, img->width, img->height,\n                                    planes[0], planes[1], planes[2], NULL);\n    free(planes[0]);\n    free(planes[1]);\n    free(planes[2]);\n    return rc;\n}\nint print_audio_devices()\n{\n    int i = 0;\n\n    for (i = 0; i < Pa_GetDeviceCount(); ++i) {\n        const PaDeviceInfo *info = Pa_GetDeviceInfo(i);\n\n        if (info)\n            printf(\"%d) %s\\n\", i, info->name);\n    }\n\n    return 0;\n}\nint print_help (const char *name)\n{\n    printf(\"Usage: %s -[a:v:o:dh]\\n\"\n           \"-a <path> audio input file\\n\"\n           \"-b <ms> audio frame duration\\n\"\n           \"-v <path> video input file\\n\"\n           \"-x <ms> video frame duration\\n\"\n           \"-o <idx> output audio device index\\n\"\n           \"-d print output audio devices\\n\"\n           \"-h print this help\\n\", name);\n\n    return 0;\n}\n\nint main (int argc, char **argv)\n{\n    freopen(\"/dev/zero\", \"w\", stderr);\n    Pa_Initialize();\n\n    struct stat st;\n\n    /* AV files for testing */\n    const char *af_name = NULL;\n    const char *vf_name = NULL;\n    long audio_out_dev_idx = -1;\n\n    int32_t audio_frame_duration = 20;\n    int32_t video_frame_duration = 10;\n\n    /* Parse settings */\nCHECK_ARG:\n\n    switch (getopt(argc, argv, \"a:b:v:x:o:dh\")) {\n        case 'a':\n            af_name = optarg;\n            goto CHECK_ARG;\n\n        case 'b': {\n            char *d;\n            audio_frame_duration = strtol(optarg, &d, 10);\n\n            if (*d) {\n                printf(\"Invalid value for argument: 'b'\");\n                exit(1);\n            }\n\n            goto CHECK_ARG;\n        }\n\n        case 'v':\n            vf_name = optarg;\n            goto CHECK_ARG;\n\n        case 'x': {\n            char *d;\n            video_frame_duration = strtol(optarg, &d, 10);\n\n            if (*d) {\n                printf(\"Invalid value for argument: 'x'\");\n                exit(1);\n            }\n\n            goto CHECK_ARG;\n        }\n\n        case 'o': {\n            char *d;\n            audio_out_dev_idx = strtol(optarg, &d, 10);\n\n            if (*d) {\n                printf(\"Invalid value for argument: 'o'\");\n                exit(1);\n            }\n\n            goto CHECK_ARG;\n        }\n\n        case 'd':\n            return print_audio_devices();\n\n        case 'h':\n            return print_help(argv[0]);\n\n        case '?':\n            exit(1);\n\n        case -1:\n            ;\n    }\n\n    { /* Check files */\n        if (!af_name) {\n            printf(\"Required audio input file!\\n\");\n            exit(1);\n        }\n\n        if (!vf_name) {\n            printf(\"Required video input file!\\n\");\n            exit(1);\n        }\n\n        /* Check for files */\n        if (stat(af_name, &st) != 0 || !S_ISREG(st.st_mode)) {\n            printf(\"%s doesn't seem to be a regular file!\\n\", af_name);\n            exit(1);\n        }\n\n        if (stat(vf_name, &st) != 0 || !S_ISREG(st.st_mode)) {\n            printf(\"%s doesn't seem to be a regular file!\\n\", vf_name);\n            exit(1);\n        }\n    }\n\n    if (audio_out_dev_idx < 0)\n        audio_out_dev_idx = Pa_GetDefaultOutputDevice();\n\n    const PaDeviceInfo *audio_dev = Pa_GetDeviceInfo(audio_out_dev_idx);\n\n    if (!audio_dev) {\n        fprintf(stderr, \"Device under index: %ld invalid\", audio_out_dev_idx);\n        return 1;\n    }\n\n    printf(\"Using audio device: %s\\n\", audio_dev->name);\n    printf(\"Using audio file: %s\\n\", af_name);\n    printf(\"Using video file: %s\\n\", vf_name);\n\n    /* START TOX NETWORK */\n\n    Tox *bootstrap;\n    ToxAV *AliceAV;\n    ToxAV *BobAV;\n\n    CallControl AliceCC;\n    CallControl BobCC;\n\n    initialize_tox(&bootstrap, &AliceAV, &AliceCC, &BobAV, &BobCC);\n\n    if (TEST_TRANSFER_A) {\n        SNDFILE *af_handle;\n        SF_INFO af_info;\n\n        printf(\"\\nTrying audio enc/dec...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        pthread_mutex_init(AliceCC.arb_mutex, NULL);\n        pthread_mutex_init(BobCC.arb_mutex, NULL);\n\n        AliceCC.arb = rb_new(16);\n        BobCC.arb = rb_new(16);\n\n        { /* Call */\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                exit(1);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, AliceAV, BobAV);\n\n        { /* Answer */\n            TOXAV_ERR_ANSWER rc;\n            toxav_answer(BobAV, 0, 48, 0, &rc);\n\n            if (rc != TOXAV_ERR_ANSWER_OK) {\n                printf(\"toxav_answer failed: %d\\n\", rc);\n                exit(1);\n            }\n        }\n\n        while (AliceCC.state == 0)\n            iterate_tox(bootstrap, AliceAV, BobAV);\n\n        /* Open audio file */\n        af_handle = sf_open(af_name, SFM_READ, &af_info);\n\n        if (af_handle == NULL) {\n            printf(\"Failed to open the file.\\n\");\n            exit(1);\n        }\n\n        int16_t PCM[5760];\n\n        time_t start_time = time(NULL);\n        time_t expected_time = af_info.frames / af_info.samplerate + 2;\n\n\n        /* Start decode thread */\n        struct toxav_thread_data data = {\n            .AliceAV = AliceAV,\n            .BobAV = BobAV,\n            .sig = 0\n        };\n\n        pthread_t dect;\n        pthread_create(&dect, NULL, iterate_toxav, &data);\n        pthread_detach(dect);\n\n        int frame_size = (af_info.samplerate * audio_frame_duration / 1000) * af_info.channels;\n\n        struct PaStreamParameters output;\n        output.device = audio_out_dev_idx;\n        output.channelCount = af_info.channels;\n        output.sampleFormat = paInt16;\n        output.suggestedLatency = audio_dev->defaultHighOutputLatency;\n        output.hostApiSpecificStreamInfo = NULL;\n\n        PaError err = Pa_OpenStream(&adout, NULL, &output, af_info.samplerate, frame_size, paNoFlag, NULL, NULL);\n        assert(err == paNoError);\n\n        err = Pa_StartStream(adout);\n        assert(err == paNoError);\n\n//         toxav_audio_bit_rate_set(AliceAV, 0, 64, false, NULL);\n\n        /* Start write thread */\n        pthread_t t;\n        pthread_create(&t, NULL, pa_write_thread, &BobCC);\n        pthread_detach(t);\n\n        printf(\"Sample rate %d\\n\", af_info.samplerate);\n\n        while (start_time + expected_time > time(NULL) ) {\n            uint64_t enc_start_time = current_time_monotonic();\n            int64_t count = sf_read_short(af_handle, PCM, frame_size);\n\n            if (count > 0) {\n                TOXAV_ERR_SEND_FRAME rc;\n\n                if (toxav_audio_send_frame(AliceAV, 0, PCM, count / af_info.channels, af_info.channels, af_info.samplerate,\n                                           &rc) == false) {\n                    printf(\"Error sending frame of size %ld: %d\\n\", count, rc);\n                }\n            }\n\n            iterate_tox(bootstrap, AliceAV, BobAV);\n            c_sleep(abs(audio_frame_duration - (current_time_monotonic() - enc_start_time) - 1));\n        }\n\n        printf(\"Played file in: %lu; stopping stream...\\n\", time(NULL) - start_time);\n\n        Pa_StopStream(adout);\n        sf_close(af_handle);\n\n        { /* Hangup */\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                exit(1);\n            }\n        }\n\n        iterate_tox(bootstrap, AliceAV, BobAV);\n        assert(BobCC.state == TOXAV_FRIEND_CALL_STATE_FINISHED);\n\n        /* Stop decode thread */\n        data.sig = -1;\n\n        while (data.sig != 1)\n            pthread_yield();\n\n        pthread_mutex_destroy(AliceCC.arb_mutex);\n        pthread_mutex_destroy(BobCC.arb_mutex);\n\n        void *f = NULL;\n\n        while (rb_read(AliceCC.arb, &f))\n            free(f);\n\n        while (rb_read(BobCC.arb, &f))\n            free(f);\n\n        printf(\"Success!\");\n    }\n\n    if (TEST_TRANSFER_V) {\n        printf(\"\\nTrying video enc/dec...\\n\");\n\n        memset(&AliceCC, 0, sizeof(CallControl));\n        memset(&BobCC, 0, sizeof(CallControl));\n\n        { /* Call */\n            TOXAV_ERR_CALL rc;\n            toxav_call(AliceAV, 0, 0, 2000, &rc);\n\n            if (rc != TOXAV_ERR_CALL_OK) {\n                printf(\"toxav_call failed: %d\\n\", rc);\n                exit(1);\n            }\n        }\n\n        while (!BobCC.incoming)\n            iterate_tox(bootstrap, AliceAV, BobAV);\n\n        { /* Answer */\n            TOXAV_ERR_ANSWER rc;\n            toxav_answer(BobAV, 0, 0, 5000, &rc);\n\n            if (rc != TOXAV_ERR_ANSWER_OK) {\n                printf(\"toxav_answer failed: %d\\n\", rc);\n                exit(1);\n            }\n        }\n\n        iterate_tox(bootstrap, AliceAV, BobAV);\n\n        /* Start decode thread */\n        struct toxav_thread_data data = {\n            .AliceAV = AliceAV,\n            .BobAV = BobAV,\n            .sig = 0\n        };\n\n        pthread_t dect;\n        pthread_create(&dect, NULL, iterate_toxav, &data);\n        pthread_detach(dect);\n\n        CvCapture *capture = cvCreateFileCapture(vf_name);\n\n        if (!capture) {\n            printf(\"Failed to open video file: %s\\n\", vf_name);\n            exit(1);\n        }\n\n//         toxav_video_bit_rate_set(AliceAV, 0, 5000, false, NULL);\n\n        time_t start_time = time(NULL);\n\n        while (start_time + 90 > time(NULL)) {\n            IplImage *frame = cvQueryFrame(capture );\n\n            if (!frame)\n                break;\n\n            send_opencv_img(AliceAV, 0, frame);\n            iterate_tox(bootstrap, AliceAV, BobAV);\n            c_sleep(10);\n        }\n\n        cvReleaseCapture(&capture);\n\n        { /* Hangup */\n            TOXAV_ERR_CALL_CONTROL rc;\n            toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);\n\n            if (rc != TOXAV_ERR_CALL_CONTROL_OK) {\n                printf(\"toxav_call_control failed: %d\\n\", rc);\n                exit(1);\n            }\n        }\n\n        iterate_tox(bootstrap, AliceAV, BobAV);\n        assert(BobCC.state == TOXAV_FRIEND_CALL_STATE_FINISHED);\n\n        /* Stop decode thread */\n        printf(\"Stopping decode thread\\n\");\n        data.sig = -1;\n\n        while (data.sig != 1)\n            pthread_yield();\n\n        printf(\"Success!\");\n    }\n\n\n    Tox *Alice = toxav_get_tox(AliceAV);\n    Tox *Bob = toxav_get_tox(BobAV);\n    toxav_kill(BobAV);\n    toxav_kill(AliceAV);\n    tox_kill(Bob);\n    tox_kill(Alice);\n    tox_kill(bootstrap);\n\n    printf(\"\\nTest successful!\\n\");\n\n    Pa_Terminate();\n    return 0;\n}\n"
  },
  {
    "path": "testing/dns3_test.c",
    "content": "\n\n#include \"../toxdns/toxdns.h\"\n#include \"../toxcore/tox.h\"\n#include \"../toxcore/network.h\"\n#include \"misc_tools.c\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n\n#define c_sleep(x) Sleep(1*x)\n\n#else\n#define c_sleep(x) usleep(1000*x)\n\n#endif\n\nuint32_t create_packet(uint8_t *packet, uint8_t *string, uint8_t str_len, uint8_t id)\n{\n    memset(packet, 0, str_len + 13 + 16);\n    packet[0] = id;\n    packet[1] = rand();\n    packet[5] = 1;\n    packet[11] = 1;\n    packet[12] = '.';\n    memcpy(packet + 13, string, str_len);\n    uint32_t i, c = 0;\n\n    for (i = str_len + 12; i != 11; --i) {\n        if (packet[i] == '.') {\n            packet[i] = c;\n            c = 0;\n        } else {\n            ++c;\n        }\n    }\n\n    packet[str_len + 13 + 2] = 16;\n    packet[str_len + 13 + 4] = 1;\n    packet[str_len + 13 + 7] = 0x29;\n    packet[str_len + 13 + 8] = 16;\n    packet[str_len + 13 + 12] = 0x80;\n    return str_len + 13 + 16;\n}\n\nint main(int argc, char *argv[])\n{\n    if (argc < 4) {\n        printf(\"Usage: %s domain domain_public_key queried_username\\nEX: %s utox.org D3154F65D28A5B41A05D4AC7E4B39C6B1C233CC857FB365C56E8392737462A12 username\\n\",\n               argv[0], argv[0]);\n        exit(0);\n    }\n\n    IP ip = {0};\n    ip.family = AF_INET;\n    sock_t sock = socket(ip.family, SOCK_DGRAM, IPPROTO_UDP);\n\n    if (!sock_valid(sock))\n        return -1;\n\n    if (!addr_resolve_or_parse_ip(argv[1], &ip, 0))\n        return -1;\n\n    struct sockaddr_in target;\n    size_t addrsize = sizeof(struct sockaddr_in);\n    target.sin_family = AF_INET;\n    target.sin_addr = ip.ip4.in_addr;\n    target.sin_port = htons(53);\n\n    uint8_t string[1024] = {0};\n    void *d = tox_dns3_new(hex_string_to_bin(argv[2]));\n    unsigned int i;\n    uint32_t request_id;\n    /*\n    for (i = 0; i < 255; ++i) {\n        tox_generate_dns3_string(d, string, sizeof(string), &request_id, string, i);\n        printf(\"%s\\n\", string);\n    }*/\n    int len = tox_generate_dns3_string(d, string + 1, sizeof(string) - 1, &request_id, (uint8_t *)argv[3], strlen(argv[3]));\n\n    if (len == -1)\n        return -1;\n\n    string[0] = '_';\n    memcpy(string + len + 1, \"._tox.\", sizeof(\"._tox.\"));\n    memcpy((char *)(string + len + 1 + sizeof(\"._tox.\") - 1), argv[1], strlen(argv[1]));\n    uint8_t packet[512];\n    uint8_t id = rand();\n    uint32_t p_len = create_packet(packet, string, strlen((char *)string), id);\n\n    if (sendto(sock, (char *) packet, p_len, 0, (struct sockaddr *)&target, addrsize) != p_len)\n        return -1;\n\n    uint8_t buffer[512] = {};\n    int r_len = recv(sock, buffer, sizeof(buffer), 0);\n\n    if (r_len < (int)p_len)\n        return -1;\n\n    for (i = r_len - 1; i != 0 && buffer[i] != '='; --i);\n\n    uint8_t tox_id[TOX_ADDRESS_SIZE];\n\n    if (tox_decrypt_dns3_TXT(d, tox_id, buffer + i + 1, r_len - (i + 1), request_id) != 0)\n        return -1;\n\n    printf(\"The Tox id for username %s is:\\n\", argv[3]);\n\n    //unsigned int i;\n    for (i = 0; i < TOX_ADDRESS_SIZE; ++i) {\n        printf(\"%02hhX\", tox_id[i]);\n    }\n\n    printf(\"\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "testing/irc_syncbot.c",
    "content": "\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n#include <time.h>\n\n\n#include <fcntl.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <errno.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <netdb.h>\n#include <unistd.h>\n\n#include <sys/ioctl.h>\n\n#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MACH__)\n#define MSG_NOSIGNAL 0\n#endif\n\n//IRC name and channel.\n#define IRC_NAME \"Tox_syncbot\"\n#define IRC_CHANNEL \"#tox-real-ontopic\"\n\n//IRC server ip and port.\nuint8_t ip[4] = {127, 0, 0, 1};\nuint16_t port = 6667;\n\n#define SILENT_TIMEOUT 20\n\nint sock;\n\n#define SERVER_CONNECT \"NICK \"IRC_NAME\"\\nUSER \"IRC_NAME\" 8 * :\"IRC_NAME\"\\n\"\n#define CHANNEL_JOIN \"JOIN \"IRC_CHANNEL\"\\n\"\n\n/* In toxcore/network.c */\nuint64_t current_time_monotonic(void);\n\nuint64_t get_monotime_sec(void)\n{\n    return current_time_monotonic() / 1000;\n}\n\nint reconnect(void)\n{\n    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\n    if (sock < 0) {\n        printf(\"error socket\\n\");\n        return -1;\n    }\n\n    struct sockaddr_storage addr = {0};\n\n    size_t addrsize;\n\n    struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;\n\n    addrsize = sizeof(struct sockaddr_in);\n\n    addr4->sin_family = AF_INET;\n\n    memcpy(&addr4->sin_addr, ip, 4);\n\n    addr4->sin_port = htons(port);\n\n    if (connect(sock, (struct sockaddr *)&addr, addrsize) != 0) {\n        printf(\"error connect\\n\");\n        return -1;\n    }\n\n    send(sock, SERVER_CONNECT, sizeof(SERVER_CONNECT) - 1, MSG_NOSIGNAL);\n\n    return sock;\n}\n\n#include \"../toxcore/tox.h\"\n#include \"misc_tools.c\"\n\nint current_group = -1;\n\nstatic void callback_group_invite(Tox *tox, int fid, uint8_t type, const uint8_t *data, uint16_t length, void *userdata)\n{\n    if (current_group == -1)\n        current_group = tox_join_groupchat(tox, fid, data, length);\n}\n\nvoid callback_friend_message(Tox *tox, uint32_t fid, TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length,\n                             void *userdata)\n{\n    if (length == 1 && *message == 'c') {\n        if (tox_del_groupchat(tox, current_group) == 0)\n            current_group = -1;\n    }\n\n    if (length == 1 && *message == 'i') {\n        tox_invite_friend(tox, fid, current_group);\n    }\n\n    if (length == 1 && *message == 'j' && sock >= 0) {\n        send(sock, CHANNEL_JOIN, sizeof(CHANNEL_JOIN) - 1, MSG_NOSIGNAL);\n    }\n}\n\nstatic void copy_groupmessage(Tox *tox, int groupnumber, int friendgroupnumber, const uint8_t *message, uint16_t length,\n                              void *userdata)\n{\n    if (tox_group_peernumber_is_ours(tox, groupnumber, friendgroupnumber))\n        return;\n\n    uint8_t name[TOX_MAX_NAME_LENGTH];\n    int namelen = tox_group_peername(tox, groupnumber, friendgroupnumber, name);\n\n    if (namelen == 0 || namelen == -1) {\n        memcpy(name, \"<unknown>\", 9);\n        namelen = 9;\n    }\n\n    uint8_t sendbuf[2048];\n    uint16_t send_len = 0;\n\n    memcpy(sendbuf, \"PRIVMSG \"IRC_CHANNEL\" :\", sizeof(\"PRIVMSG \"IRC_CHANNEL\" :\"));\n    send_len += sizeof(\"PRIVMSG \"IRC_CHANNEL\" :\") - 1;\n    memcpy(sendbuf + send_len, name, namelen);\n    send_len += namelen;\n    sendbuf[send_len] = ':';\n    send_len += 1;\n    sendbuf[send_len] = ' ';\n    send_len += 1;\n    memcpy(sendbuf + send_len, message, length);\n    send_len += length;\n    unsigned int i;\n\n    for (i = 0; i < send_len; ++i) {\n        if (sendbuf[i] == '\\n')\n            sendbuf[i] = '|';\n\n        if (sendbuf[i] == 0)\n            sendbuf[i] = ' ';\n    }\n\n    sendbuf[send_len] = '\\n';\n    send_len += 1;\n\n    if (sock >= 0)\n        send(sock, sendbuf, send_len, MSG_NOSIGNAL);\n}\n\nvoid send_irc_group(Tox *tox, uint8_t *msg, uint16_t len)\n{\n    if (len > 1350 || len == 0 || len == 1)\n        return;\n\n    --len;\n\n    if (*msg != ':')\n        return;\n\n    uint8_t req[len];\n    unsigned int i;\n\n    unsigned int spaces = 0;\n\n    for (i = 0; i < (len - 1); ++i) {\n        if (msg[i + 1] == ' ') {\n            ++spaces;\n        } else {\n            if (spaces >= 3 && msg[i + 1] == ':') {\n                break;\n            }\n        }\n\n        req[i] = msg[i + 1];\n    }\n\n    unsigned int req_len = i;\n    req[i] = 0;\n\n    uint8_t message[len];\n    uint16_t length = 0;\n\n    uint8_t *pmsg = (uint8_t *)strstr((char *)req, \" PRIVMSG\");\n\n    if (pmsg == NULL)\n        return;\n\n    uint8_t *dt = req;\n\n    for (dt = req, i = 0; dt != pmsg && *dt != '!'; ++dt, ++i) {\n        message[i] = *dt;\n        ++length;\n    }\n\n    message[length] = ':';\n    length += 1;\n    message[length] = ' ';\n    length += 1;\n\n    if ((req_len + 2) >= len)\n        return;\n\n    memcpy(message + length, msg + req_len + 2, len - (req_len + 2));\n    length += len - (req_len + 2);\n    tox_group_message_send(tox, current_group, message, length);\n}\n\nTox *init_tox(int argc, char *argv[])\n{\n    uint8_t ipv6enabled = 1; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    /* with optional --ipvx, now it can be 1-4 arguments... */\n    if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) {\n        printf(\"Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\\n\", argv[0]);\n        exit(0);\n    }\n\n    Tox *tox = tox_new(0, 0);\n\n    if (!tox)\n        exit(1);\n\n    tox_self_set_name(tox, (uint8_t *)IRC_NAME, sizeof(IRC_NAME) - 1, 0);\n    tox_callback_friend_message(tox, &callback_friend_message, 0);\n    tox_callback_group_invite(tox, &callback_group_invite, 0);\n    tox_callback_group_message(tox, &copy_groupmessage, 0);\n    tox_callback_group_action(tox, &copy_groupmessage, 0);\n\n    char temp_id[128];\n    printf(\"\\nEnter the address of irc_syncbots master (38 bytes HEX format):\\n\");\n\n    if (scanf(\"%s\", temp_id) != 1) {\n        exit (1);\n    }\n\n    uint16_t port = atoi(argv[argvoffset + 2]);\n    unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);\n    tox_bootstrap(tox, argv[argvoffset + 1], port, binary_string, 0);\n    free(binary_string);\n\n    uint8_t *bin_id = hex_string_to_bin(temp_id);\n    uint32_t num = tox_friend_add(tox, bin_id, (uint8_t *)\"Install Gentoo\", sizeof(\"Install Gentoo\") - 1, 0);\n    free(bin_id);\n\n    if (num == UINT32_MAX) {\n        printf(\"\\nSomething went wrong when adding friend.\\n\");\n        exit(1);\n    }\n\n    return tox;\n}\n\nint main(int argc, char *argv[])\n{\n    Tox *tox = init_tox(argc, argv);\n\n    sock = reconnect();\n\n    if (sock < 0)\n        return 1;\n\n    uint64_t last_get = get_monotime_sec();\n    int connected = 0, ping_sent = 0;\n\n    while (1) {\n        int count = 0;\n        ioctl(sock, FIONREAD, &count);\n\n        if (count > 0) {\n            last_get = get_monotime_sec();\n            ping_sent = 0;\n            uint8_t data[count + 1];\n            data[count] = 0;\n            recv(sock, data, count, MSG_NOSIGNAL);\n            printf(\"%s\", data);\n\n            if (!connected)\n                connected = 1;\n\n            if (count > 6 && data[0] == 'P' && data[1] == 'I' && data[2] == 'N' && data[3] == 'G') {\n                data[1] = 'O';\n                unsigned int i;\n\n                for (i = 0; i < count; ++i) {\n                    if (data[i] == '\\n') {\n                        ++i;\n                        break;\n                    }\n                }\n\n                send(sock, data, i, MSG_NOSIGNAL);\n            }\n\n            unsigned int i, p_i = 0;\n\n            for (i = 1; data[0] == ':' && i < count; ++i) {\n                if (data[i] == ' ') {\n                    if (i + 5 < count && memcmp(data + i, \" 404 \", 5) == 0) {\n                        connected = 1;\n                    }\n\n                    break;\n                }\n\n                if (data[i] == ':')\n                    break;\n            }\n\n            for (i = 0; i < count; ++i) {\n                if (data[i] == '\\n' && i != 0) {\n                    send_irc_group(tox, data + p_i, i - p_i);\n                    p_i = i + 1;\n                }\n            }\n        }\n\n        if (connected == 1) {\n            send(sock, CHANNEL_JOIN, sizeof(CHANNEL_JOIN) - 1, MSG_NOSIGNAL);\n            connected = 2;\n        }\n\n        if (!ping_sent && last_get + (SILENT_TIMEOUT / 2) < get_monotime_sec()) {\n            unsigned int p_s = sizeof(\"PING :test\\n\") - 1;\n\n            if (send(sock, \"PING :test\\n\", p_s, MSG_NOSIGNAL) == p_s)\n                ping_sent = 1;\n        }\n\n        int error = 0;\n        socklen_t len = sizeof (error);\n\n        if (sock < 0 || last_get + SILENT_TIMEOUT < get_monotime_sec()\n                || getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len ) != 0) {\n            close(sock);\n            printf(\"reconnect\\n\");\n            sock = reconnect();\n\n            if (sock >= 0) {\n                last_get = get_monotime_sec();\n                connected = 0;\n                ping_sent = 0;\n            }\n        }\n\n        tox_iterate(tox);\n        usleep(1000 * 50);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "testing/misc_tools.c",
    "content": "/* misc_tools.c\n *\n * Miscellaneous functions and data structures for doing random things.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdint.h>\n\n#ifdef DEBUG\n#include <assert.h>\n#endif // DEBUG\n\n// You are responsible for freeing the return value!\nuint8_t *hex_string_to_bin(char *hex_string)\n{\n    // byte is represented by exactly 2 hex digits, so lenth of binary string\n    // is half of that of the hex one. only hex string with even length\n    // valid. the more proper implementation would be to check if strlen(hex_string)\n    // is odd and return error code if it is. we assume strlen is even. if it's not\n    // then the last byte just won't be written in 'ret'.\n    size_t i, len = strlen(hex_string) / 2;\n    uint8_t *ret = malloc(len);\n    char *pos = hex_string;\n\n    for (i = 0; i < len; ++i, pos += 2)\n        sscanf(pos, \"%2hhx\", &ret[i]);\n\n    return ret;\n}\n\nint cmdline_parsefor_ipv46(int argc, char **argv, uint8_t *ipv6enabled)\n{\n    int argvoffset = 0, argi;\n\n    for (argi = 1; argi < argc; argi++)\n        if (!strncasecmp(argv[argi], \"--ipv\", 5)) {\n            if (argv[argi][5] && !argv[argi][6]) {\n                char c = argv[argi][5];\n\n                if (c == '4')\n                    *ipv6enabled = 0;\n                else if (c == '6')\n                    *ipv6enabled = 1;\n                else {\n                    printf(\"Invalid argument: %s. Try --ipv4 or --ipv6!\\n\", argv[argi]);\n                    return -1;\n                }\n            } else {\n                printf(\"Invalid argument: %s. Try --ipv4 or --ipv6!\\n\", argv[argi]);\n                return -1;\n            }\n\n            if (argvoffset != argi - 1) {\n                printf(\"Argument must come first: %s.\\n\", argv[argi]);\n                return -1;\n            }\n\n            argvoffset++;\n        }\n\n    return argvoffset;\n};\n"
  },
  {
    "path": "testing/nTox.c",
    "content": "/* nTox.c\n *\n * Textual frontend for Tox.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define _WIN32_WINNT 0x501\n#include <winsock2.h>\n#include <ws2tcpip.h>\n#else\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <sys/types.h>\n#include <netdb.h>\n#endif\n\n#include <sys/select.h>\n\n#include \"nTox.h\"\n#include \"misc_tools.c\"\n\n#include <stdio.h>\n#include <time.h>\n#include <locale.h>\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#define c_sleep(x) Sleep(1*x)\n#else\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n#endif\n\nchar lines[HISTORY][STRING_LENGTH];\nuint8_t flag[HISTORY];\nchar input_line[STRING_LENGTH];\n\n/* wrap: continuation mark */\nconst size_t wrap_cont_len = 3;\nconst char wrap_cont_str[] = \"\\n+ \";\n\n#define STRING_LENGTH_WRAPPED (STRING_LENGTH + 16 * (wrap_cont_len + 1))\n\n/* documented: fdmnlsahxgiztq(c[rfg]) */\n/* undocumented: d (tox_do()) */\n\n/* 251+1 characters */\nchar *help_main =\n    \"[i] Available main commands:\\n+ \"\n    \"/x (to print one's own id)|\"\n    \"/s status (to change status, e.g. AFK)|\"\n    \"/n nick (to change your nickname)|\"\n    \"/q (to quit)|\"\n    \"/cr (to reset conversation)|\"\n    \"/h friend (for friend related commands)|\"\n    \"/h group (for group related commands)\";\n\n/* 190+1 characters */\nchar *help_friend1 =\n    \"[i] Available friend commands (1/2):\\n+ \"\n    \"/l list (to list friends)|\"\n    \"/r friend no. (to remove from the friend list)|\"\n    \"/f ID (to send a friend request)|\"\n    \"/a request no. (to accept a friend request)\";\n\n/* 187+1 characters */\nchar *help_friend2 =\n    \"[i] Available friend commands (2/2):\\n+ \"\n    \"/m friend no. message (to send a message)|\"\n    \"/t friend no. filename (to send a file to a friend)|\"\n    \"/cf friend no. (to talk to that friend per default)\";\n\n/* 253+1 characters */\nchar *help_group =\n    \"[i] Available group commands:\\n+ \"\n    \"/g (to create a group)|\"\n    \"/i friend no. group no. (to invite a friend to a group)|\"\n    \"/z group no. message (to send a message to a group)|\"\n    \"/p group no. (to list a group's peers)|\"\n    \"/cg group no. (to talk to that group per default)\";\n\nint x, y;\n\nint conversation_default = 0;\n\ntypedef struct {\n    uint8_t id[TOX_PUBLIC_KEY_SIZE];\n    uint8_t accepted;\n} Friend_request;\n\nFriend_request pending_requests[256];\nuint8_t num_requests = 0;\n\n#define NUM_FILE_SENDERS 64\ntypedef struct {\n    FILE *file;\n    uint32_t friendnum;\n    uint32_t filenumber;\n} File_Sender;\nFile_Sender file_senders[NUM_FILE_SENDERS];\nuint8_t numfilesenders;\n\nvoid tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length,\n                            void *user_data)\n{\n    unsigned int i;\n\n    for (i = 0; i < NUM_FILE_SENDERS; ++i) {\n        /* This is slow */\n        if (file_senders[i].file && file_senders[i].friendnum == friend_number && file_senders[i].filenumber == file_number) {\n            if (length == 0) {\n                fclose(file_senders[i].file);\n                file_senders[i].file = 0;\n                char msg[512];\n                sprintf(msg, \"[t] %u file transfer: %u completed\", file_senders[i].friendnum, file_senders[i].filenumber);\n                new_lines(msg);\n                break;\n            }\n\n            fseek(file_senders[i].file, position, SEEK_SET);\n            uint8_t data[length];\n            int len = fread(data, 1, length, file_senders[i].file);\n            tox_file_send_chunk(tox, friend_number, file_number, position, data, len, 0);\n            break;\n        }\n    }\n}\n\n\nuint32_t add_filesender(Tox *m, uint16_t friendnum, char *filename)\n{\n    FILE *tempfile = fopen(filename, \"rb\");\n\n    if (tempfile == 0)\n        return -1;\n\n    fseek(tempfile, 0, SEEK_END);\n    uint64_t filesize = ftell(tempfile);\n    fseek(tempfile, 0, SEEK_SET);\n    uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, 0, (uint8_t *)filename,\n                                     strlen(filename), 0);\n\n    if (filenum == -1)\n        return -1;\n\n    file_senders[numfilesenders].file = tempfile;\n    file_senders[numfilesenders].friendnum = friendnum;\n    file_senders[numfilesenders].filenumber = filenum;\n    ++numfilesenders;\n    return filenum;\n}\n\n\n\n#define FRADDR_TOSTR_CHUNK_LEN 8\n#define FRADDR_TOSTR_BUFSIZE (TOX_ADDRESS_SIZE * 2 + TOX_ADDRESS_SIZE / FRADDR_TOSTR_CHUNK_LEN + 1)\n\nstatic void fraddr_to_str(uint8_t *id_bin, char *id_str)\n{\n    uint32_t i, delta = 0, pos_extra, sum_extra = 0;\n\n    for (i = 0; i < TOX_ADDRESS_SIZE; i++) {\n        sprintf(&id_str[2 * i + delta], \"%02hhX\", id_bin[i]);\n\n        if ((i + 1) == TOX_PUBLIC_KEY_SIZE)\n            pos_extra = 2 * (i + 1) + delta;\n\n        if (i >= TOX_PUBLIC_KEY_SIZE)\n            sum_extra |= id_bin[i];\n\n        if (!((i + 1) % FRADDR_TOSTR_CHUNK_LEN)) {\n            id_str[2 * (i + 1) + delta] = ' ';\n            delta++;\n        }\n    }\n\n    id_str[2 * i + delta] = 0;\n\n    if (!sum_extra)\n        id_str[pos_extra] = 0;\n}\n\nvoid get_id(Tox *m, char *data)\n{\n    sprintf(data, \"[i] ID: \");\n    int offset = strlen(data);\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(m, address);\n    fraddr_to_str(address, data + offset);\n}\n\nint getfriendname_terminated(Tox *m, int friendnum, char *namebuf)\n{\n    tox_friend_get_name(m, friendnum, (uint8_t *)namebuf, NULL);\n    int res = tox_friend_get_name_size(m, friendnum, NULL);\n\n    if (res >= 0)\n        namebuf[res] = 0;\n    else\n        namebuf[0] = 0;\n\n    return res;\n}\n\nvoid new_lines_mark(char *line, uint8_t special)\n{\n    int i = 0;\n\n    for (i = HISTORY - 1; i > 0; i--) {\n        strncpy(lines[i], lines[i - 1], STRING_LENGTH - 1);\n        flag[i] = flag[i - 1];\n    }\n\n    strncpy(lines[0], line, STRING_LENGTH - 1);\n    flag[i] = special;\n\n    do_refresh();\n}\n\nvoid new_lines(char *line)\n{\n    new_lines_mark(line, 0);\n}\n\n\nconst char ptrn_friend[] = \"[i] Friend %i: %s\\n+ id: %s\";\nconst int id_str_len = TOX_ADDRESS_SIZE * 2 + 3;\nvoid print_friendlist(Tox *m)\n{\n    new_lines(\"[i] Friend List:\");\n\n    char name[TOX_MAX_NAME_LENGTH + 1];\n    uint8_t fraddr_bin[TOX_ADDRESS_SIZE];\n    char fraddr_str[FRADDR_TOSTR_BUFSIZE];\n\n    /* account for the longest name and the longest \"base\" string and number (int) and id_str */\n    char fstring[TOX_MAX_NAME_LENGTH + strlen(ptrn_friend) + 21 + id_str_len];\n\n    uint32_t i = 0;\n\n    while (getfriendname_terminated(m, i, name) != -1) {\n        if (tox_friend_get_public_key(m, i, fraddr_bin, NULL))\n            fraddr_to_str(fraddr_bin, fraddr_str);\n        else\n            sprintf(fraddr_str, \"???\");\n\n        if (strlen(name) <= 0) {\n            sprintf(fstring, ptrn_friend, i, \"No name?\", fraddr_str);\n        } else {\n            sprintf(fstring, ptrn_friend, i, (uint8_t *)name, fraddr_str);\n        }\n\n        i++;\n        new_lines(fstring);\n    }\n\n    if (i == 0)\n        new_lines(\"+ no friends! D:\");\n}\n\nstatic int fmtmsg_tm_mday = -1;\n\nstatic void print_formatted_message(Tox *m, char *message, int friendnum, uint8_t outgoing)\n{\n    char name[TOX_MAX_NAME_LENGTH + 1];\n    getfriendname_terminated(m, friendnum, name);\n\n    char msg[100 + strlen(message) + strlen(name) + 1];\n\n    time_t rawtime;\n    struct tm *timeinfo;\n    time ( &rawtime );\n    timeinfo = localtime ( &rawtime );\n\n    /* assume that printing the date once a day is enough */\n    if (fmtmsg_tm_mday != timeinfo->tm_mday) {\n        fmtmsg_tm_mday = timeinfo->tm_mday;\n        /* strftime(msg, 100, \"Today is %a %b %d %Y.\", timeinfo); */\n        /* %x is the locale's preferred date format */\n        strftime(msg, 100, \"Today is %x.\", timeinfo);\n        new_lines(msg);\n    }\n\n    char time[64];\n    /* strftime(time, 64, \"%I:%M:%S %p\", timeinfo); */\n    /* %X is the locale's preferred time format */\n    strftime(time, 64, \"%X\", timeinfo);\n\n    if (outgoing) {\n        /* tgt: friend */\n        sprintf(msg, \"[%d] %s =>{%s} %s\", friendnum, time, name, message);\n    } else {\n        /* src: friend */\n        sprintf(msg, \"[%d] %s <%s>: %s\", friendnum, time, name, message);\n    }\n\n    new_lines(msg);\n}\n\n/* forward declarations */\nstatic int save_data(Tox *m);\nvoid print_groupchatpeers(Tox *m, int groupnumber);\n\nvoid line_eval(Tox *m, char *line)\n{\n    if (line[0] == '/') {\n        char inpt_command = line[1];\n        char prompt[STRING_LENGTH + 2] = \"> \";\n        int prompt_offset = 3;\n        strcat(prompt, line);\n        new_lines(prompt);\n\n        if (inpt_command == 'f') { // add friend command: /f ID\n            int i, delta = 0;\n            char temp_id[128];\n\n            for (i = 0; i < 128; i++) {\n                temp_id[i - delta] = line[i + prompt_offset];\n\n                if ((temp_id[i - delta] == ' ') || (temp_id[i - delta] == '+'))\n                    delta++;\n            }\n\n            unsigned char *bin_string = hex_string_to_bin(temp_id);\n            TOX_ERR_FRIEND_ADD error;\n            uint32_t num = tox_friend_add(m, bin_string, (uint8_t *)\"Install Gentoo\", sizeof(\"Install Gentoo\"), &error);\n            free(bin_string);\n            char numstring[100];\n\n            switch (error) {\n                case TOX_ERR_FRIEND_ADD_TOO_LONG:\n                    sprintf(numstring, \"[i] Message is too long.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_NO_MESSAGE:\n                    sprintf(numstring, \"[i] Please add a message to your request.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_OWN_KEY:\n                    sprintf(numstring, \"[i] That appears to be your own ID.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_ALREADY_SENT:\n                    sprintf(numstring, \"[i] Friend request already sent.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_BAD_CHECKSUM:\n                    sprintf(numstring, \"[i] Address has a bad checksum.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM:\n                    sprintf(numstring, \"[i] New nospam set.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_MALLOC:\n                    sprintf(numstring, \"[i] malloc error.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_NULL:\n                    sprintf(numstring, \"[i] message was NULL.\");\n                    break;\n\n                case TOX_ERR_FRIEND_ADD_OK:\n                    sprintf(numstring, \"[i] Added friend as %d.\", num);\n                    save_data(m);\n                    break;\n            }\n\n            new_lines(numstring);\n        } else if (inpt_command == 'd') {\n            tox_iterate(m);\n        } else if (inpt_command == 'm') { //message command: /m friendnumber messsage\n            char *posi[1];\n            int num = strtoul(line + prompt_offset, posi, 0);\n\n            if (**posi != 0) {\n                if (tox_friend_send_message(m, num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) *posi + 1, strlen(*posi + 1), NULL) < 1) {\n                    char sss[256];\n                    sprintf(sss, \"[i] could not send message to friend num %u\", num);\n                    new_lines(sss);\n                } else {\n                    print_formatted_message(m, *posi + 1, num, 1);\n                }\n            } else\n                new_lines(\"Error, bad input.\");\n        } else if (inpt_command == 'n') {\n            uint8_t name[TOX_MAX_NAME_LENGTH];\n            size_t i, len = strlen(line);\n\n            for (i = 3; i < len; i++) {\n                if (line[i] == 0 || line[i] == '\\n') break;\n\n                name[i - 3] = line[i];\n            }\n\n            name[i - 3] = 0;\n            tox_self_set_name(m, name, i - 2, NULL);\n            char numstring[100];\n            sprintf(numstring, \"[i] changed nick to %s\", (char *)name);\n            new_lines(numstring);\n        } else if (inpt_command == 'l') {\n            print_friendlist(m);\n        } else if (inpt_command == 's') {\n            uint8_t status[TOX_MAX_STATUS_MESSAGE_LENGTH];\n            size_t i, len = strlen(line);\n\n            for (i = 3; i < len; i++) {\n                if (line[i] == 0 || line[i] == '\\n') break;\n\n                status[i - 3] = line[i];\n            }\n\n            status[i - 3] = 0;\n            tox_self_set_status_message(m, status, strlen((char *)status), NULL);\n            char numstring[100];\n            sprintf(numstring, \"[i] changed status to %s\", (char *)status);\n            new_lines(numstring);\n        } else if (inpt_command == 'a') { // /a #: accept\n            uint8_t numf = atoi(line + 3);\n            char numchar[100];\n\n            if (numf >= num_requests || pending_requests[numf].accepted) {\n                sprintf(numchar, \"[i] you either didn't receive that request or you already accepted it\");\n                new_lines(numchar);\n            } else {\n                uint32_t num = tox_friend_add_norequest(m, pending_requests[numf].id, NULL);\n\n                if (num != UINT32_MAX) {\n                    pending_requests[numf].accepted = 1;\n                    sprintf(numchar, \"[i] friend request %u accepted as friend no. %d\", numf, num);\n                    new_lines(numchar);\n                    save_data(m);\n                } else {\n                    sprintf(numchar, \"[i] failed to add friend\");\n                    new_lines(numchar);\n                }\n            }\n        } else if (inpt_command == 'r') { // /r #: remove friend\n            uint8_t numf = atoi(line + 3);\n\n            if (!tox_friend_exists(m, numf)) {\n                char err[64];\n                sprintf(err, \"You don't have a friend %i.\", numf);\n                new_lines(err);\n                return;\n            }\n\n            char msg[128 + TOX_MAX_NAME_LENGTH];\n            char fname[TOX_MAX_NAME_LENGTH ];\n            getfriendname_terminated(m, numf, fname);\n            sprintf(msg, \"Are you sure you want to delete friend %i: %s? (y/n)\", numf, fname);\n            input_line[0] = 0;\n            new_lines(msg);\n\n            int c;\n\n            do {\n                c = getchar();\n            } while ((c != 'y') && (c != 'n') && (c != EOF));\n\n            if (c == 'y') {\n                int res = tox_friend_delete(m, numf, NULL);\n\n                if (res)\n                    sprintf(msg, \"[i] [%i: %s] is no longer your friend\", numf, fname);\n                else\n                    sprintf(msg, \"[i] failed to remove friend\");\n\n                new_lines(msg);\n            }\n        } else if (inpt_command == 'h') { //help\n            if (line[2] == ' ') {\n                if (line[3] == 'f') {\n                    new_lines_mark(help_friend1, 1);\n                    new_lines_mark(help_friend2, 1);\n                    return;\n                } else if (line[3] == 'g') {\n                    new_lines_mark(help_group, 1);\n                    return;\n                }\n            }\n\n            new_lines_mark(help_main, 1);\n        } else if (inpt_command == 'x') { //info\n            char idstring[200];\n            get_id(m, idstring);\n            new_lines(idstring);\n        } else if (inpt_command == 'g') { //create new group chat\n            char msg[256];\n            sprintf(msg, \"[g] Created new group chat with number: %u\", tox_add_groupchat(m));\n            new_lines(msg);\n        } else if (inpt_command == 'i') { //invite friendnum to groupnum\n            char *posi[1];\n            int friendnumber = strtoul(line + prompt_offset, posi, 0);\n            int groupnumber = strtoul(*posi + 1, NULL, 0);\n            char msg[256];\n            sprintf(msg, \"[g] Invited friend number %u to group number %u, returned: %u (0 means success)\", friendnumber,\n                    groupnumber, tox_invite_friend(m, friendnumber, groupnumber));\n            new_lines(msg);\n        } else if (inpt_command == 'z') { //send message to groupnum\n            char *posi[1];\n            int groupnumber = strtoul(line + prompt_offset, posi, 0);\n\n            if (**posi != 0) {\n                int res = tox_group_message_send(m, groupnumber, (uint8_t *)*posi + 1, strlen(*posi + 1));\n\n                if (res == 0) {\n                    char msg[32 + STRING_LENGTH];\n                    sprintf(msg, \"[g] #%u: YOU: %s\", groupnumber, *posi + 1);\n                    new_lines(msg);\n                } else {\n                    char msg[128];\n                    sprintf(msg, \"[i] could not send message to group no. %u: %i\", groupnumber, res);\n                    new_lines(msg);\n                }\n            }\n        } else if (inpt_command == 't') {\n            char *posi[1];\n            int friendnum = strtoul(line + prompt_offset, posi, 0);\n\n            if (**posi != 0) {\n                char msg[512];\n                sprintf(msg, \"[t] Sending file %s to friendnum %u filenumber is %i (-1 means failure)\", *posi + 1, friendnum,\n                        add_filesender(m, friendnum, *posi + 1));\n                new_lines(msg);\n            }\n        } else if (inpt_command == 'q') { //exit\n            save_data(m);\n            endwin();\n            tox_kill(m);\n            exit(EXIT_SUCCESS);\n        } else if (inpt_command == 'c') { //set conversation partner\n            if (line[2] == 'r') {\n                if (conversation_default != 0) {\n                    conversation_default = 0;\n                    new_lines(\"[i] default conversation reset\");\n                } else\n                    new_lines(\"[i] default conversation wasn't set, nothing to do\");\n            } else if (line[3] != ' ') {\n                new_lines(\"[i] invalid command\");\n            } else {\n                int num = atoi(line + 4);\n\n                /* zero is also returned for not-a-number */\n                if (!num && strcmp(line + 4, \"0\"))\n                    num = -1;\n\n                if (num < 0)\n                    new_lines(\"[i] invalid command parameter\");\n                else if (line[2] == 'f') {\n                    conversation_default = num + 1;\n                    char buffer[128];\n                    sprintf(buffer, \"[i] default conversation is now to friend %i\", num);\n                    new_lines(buffer);\n                } else if (line[2] == 'g') {\n                    char buffer[128];\n                    conversation_default = - (num + 1);\n                    sprintf(buffer, \"[i] default conversation is now to group %i\", num);\n                    new_lines(buffer);\n                } else\n                    new_lines(\"[i] invalid command\");\n            }\n        } else if (inpt_command == 'p') { //list peers\n            char *posi = NULL;\n            int group_number = strtoul(line + prompt_offset, &posi, 0);\n\n            if (posi != NULL) {\n                char msg[64];\n                int peer_cnt = tox_group_number_peers(m, group_number);\n\n                if (peer_cnt < 0) {\n                    new_lines(\"[g] Invalid group number.\");\n                } else if (peer_cnt == 0) {\n                    sprintf(msg, \"[g] #%i: No peers in group.\", group_number);\n                    new_lines(msg);\n                } else {\n                    sprintf(msg, \"[g] #%i: Group has %i peers. Names:\", group_number, peer_cnt);\n                    new_lines(msg);\n                    print_groupchatpeers(m, group_number);\n                }\n            }\n        } else {\n            new_lines(\"[i] invalid command\");\n        }\n    } else {\n        if (conversation_default != 0) {\n            if (conversation_default > 0) {\n                int friendnumber = conversation_default - 1;\n                uint32_t res = tox_friend_send_message(m, friendnumber, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *)line, strlen(line), NULL);\n\n                if (res == 0) {\n                    char sss[128];\n                    sprintf(sss, \"[i] could not send message to friend no. %u\", friendnumber);\n                    new_lines(sss);\n                } else\n                    print_formatted_message(m, line, friendnumber, 1);\n            } else {\n                int groupnumber = - conversation_default - 1;\n                int res = tox_group_message_send(m, groupnumber, (uint8_t *)line, strlen(line));\n\n                if (res == 0) {\n                    char msg[32 + STRING_LENGTH];\n                    sprintf(msg, \"[g] #%u: YOU: %s\", groupnumber, line);\n                    new_lines(msg);\n                } else {\n                    char msg[128];\n                    sprintf(msg, \"[i] could not send message to group no. %u: %i\", groupnumber, res);\n                    new_lines(msg);\n                }\n            }\n        } else\n            new_lines(\"[i] invalid input: neither command nor in conversation\");\n    }\n}\n\n/* basic wrap, ignores embedded '\\t', '\\n' or '|'\n * inserts continuation markers if there's enough space left,\n * otherwise turns spaces into newlines if possible */\nvoid wrap(char output[STRING_LENGTH_WRAPPED], char input[STRING_LENGTH], int line_width)\n{\n    size_t i, len = strlen(input);\n\n    if ((line_width < 4) || (len < (size_t)line_width)) {\n        /* if line_width ridiculously tiny, it's not worth the effort */\n        strcpy(output, input);\n        return;\n    }\n\n    /* how much can we shift? */\n    size_t delta_is = 0, delta_remain = STRING_LENGTH_WRAPPED - len - 1;\n\n    /* if the line is very very short, don't insert continuation markers,\n     * as they would use up too much of the line */\n    if ((size_t)line_width < 2 * wrap_cont_len)\n        delta_remain = 0;\n\n    for (i = line_width; i < len; i += line_width) {\n        /* look backward for a space to expand/turn into a new line */\n        size_t k = i;\n        size_t m = i - line_width;\n\n        while (input[k] != ' ' && k > m) {\n            k--;\n        }\n\n        if (k > m) {\n            if (delta_remain > wrap_cont_len) {\n                /* replace space with continuation, then\n                 * set the pos. after the space as new line start\n                 * (i.e. space is being \"eaten\") */\n                memcpy(output + m + delta_is, input + m, k - m);\n                strcpy(output + k + delta_is, wrap_cont_str);\n\n                delta_remain -= wrap_cont_len - 1;\n                delta_is += wrap_cont_len - 1;\n                i = k + 1;\n            } else {\n                /* no more space to push forward: replace the space,\n                 * use its pos. + 1 as starting point for the next line */\n                memcpy(output + m + delta_is, input + m, k - m);\n                output[k + delta_is] = '\\n';\n                i = k + 1;\n            }\n        } else {\n            /* string ends right here:\n             * don't add a continuation marker with nothing following */\n            if (i == len - 1)\n                break;\n\n            /* nothing found backwards */\n            if (delta_remain > wrap_cont_len) {\n                /* break at the end of the line,\n                 * i.e. in the middle of the word at the border */\n                memcpy(output + m + delta_is, input + m, line_width);\n                strcpy(output + i + delta_is, wrap_cont_str);\n\n                delta_remain -= wrap_cont_len;\n                delta_is += wrap_cont_len;\n            } else {\n                /* no more space to push, no space to convert:\n                 * just copy the whole line and move on;\n                 * means the line count calc'ed will be off */\n                memcpy(output + m + delta_is, input + m, line_width);\n            }\n        }\n    }\n\n    i -= line_width;\n    memcpy(output + i + delta_is, input + i, len - i);\n\n    output[len + delta_is] = 0;\n}\n\n/*\n * extended wrap, honors '\\n', accepts '|' as \"break here when necessary\"\n * marks wrapped lines with \"+ \" in front, which does expand output\n * does NOT honor '\\t': would require a lot more work (and tab width isn't always 8)\n */\nvoid wrap_bars(char output[STRING_LENGTH_WRAPPED], char input[STRING_LENGTH], size_t line_width)\n{\n    size_t len = strlen(input);\n    size_t ipos, opos = 0;\n    size_t bar_avail = 0, space_avail = 0, nl_got = 0;   /* in opos */\n\n    for (ipos = 0; ipos < len; ipos++) {\n        if (opos - nl_got < line_width) {\n            /* not yet at the limit */\n            char c = input[ipos];\n\n            if (c == ' ')\n                space_avail = opos;\n\n            output[opos++] = input[ipos];\n\n            if (opos >= STRING_LENGTH_WRAPPED) {\n                opos = STRING_LENGTH_WRAPPED - 1;\n                break;\n            }\n\n            if (c == '|') {\n                output[opos - 1] = ' ';\n                bar_avail = opos;\n\n                if (opos + 2 >= STRING_LENGTH_WRAPPED) {\n                    opos = STRING_LENGTH_WRAPPED - 1;\n                    break;\n                }\n\n                output[opos++] = '|';\n                output[opos++] = ' ';\n            }\n\n            if (c == '\\n')\n                nl_got = opos;\n\n            continue;\n        } else {\n            /* at the limit */\n            if (bar_avail > nl_got) {\n                /* overwrite */\n                memcpy(output + bar_avail - 1, wrap_cont_str, wrap_cont_len);\n                nl_got = bar_avail;\n\n                ipos--;\n                continue;\n            }\n\n            if (space_avail > nl_got) {\n                if (opos + wrap_cont_len - 1 >= STRING_LENGTH_WRAPPED) {\n                    opos = STRING_LENGTH_WRAPPED - 1;\n                    break;\n                }\n\n                /* move forward by 2 characters */\n                memmove(output + space_avail + 3, output + space_avail + 1, opos - (space_avail + 1));\n                memcpy(output + space_avail, wrap_cont_str, wrap_cont_len);\n                nl_got = space_avail + 1;\n\n                opos += 2;\n                ipos--;\n                continue;\n            }\n\n            char c = input[ipos];\n\n            if ((c == '|') || (c == ' ') || (c == '\\n')) {\n                if (opos + wrap_cont_len >= STRING_LENGTH_WRAPPED) {\n                    opos = STRING_LENGTH_WRAPPED - 1;\n                    break;\n                }\n\n                memcpy(output + opos, wrap_cont_str, wrap_cont_len);\n\n                nl_got = opos;\n                opos += wrap_cont_len;\n            }\n\n            output[opos++] = input[ipos];\n\n            if (opos >= STRING_LENGTH_WRAPPED) {\n                opos = STRING_LENGTH_WRAPPED - 1;\n                break;\n            }\n\n            continue;\n        }\n    }\n\n    if (opos >= STRING_LENGTH_WRAPPED)\n        opos = STRING_LENGTH_WRAPPED - 1;\n\n    output[opos] = 0;\n}\n\nint count_lines(char *string)\n{\n    size_t i, len = strlen(string);\n    int count = 1;\n\n    for (i = 0; i < len; i++) {\n        if (string[i] == '\\n')\n            count++;\n    }\n\n    return count;\n}\n\nchar *appender(char *str, const char c)\n{\n    size_t len = strlen(str);\n\n    if (len < STRING_LENGTH) {\n        str[len + 1] = str[len];\n        str[len] = c;\n    }\n\n    return str;\n}\n\nvoid do_refresh()\n{\n    int count = 0;\n    char wrap_output[STRING_LENGTH_WRAPPED];\n    int i;\n\n    for (i = 0; i < HISTORY; i++) {\n        if (flag[i])\n            wrap_bars(wrap_output, lines[i], x);\n        else\n            wrap(wrap_output, lines[i], x);\n\n        int L = count_lines(wrap_output);\n        count = count + L;\n\n        if (count < y) {\n            move(y - 1 - count, 0);\n            printw(\"%s\", wrap_output);\n            clrtoeol();\n        }\n    }\n\n    move(y - 1, 0);\n    clrtoeol();\n    printw(\">> \");\n    printw(\"%s\", input_line);\n    clrtoeol();\n    refresh();\n}\n\nvoid print_request(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)\n{\n    new_lines(\"[i] received friend request with message:\");\n    new_lines((char *)data);\n    char numchar[100];\n    sprintf(numchar, \"[i] accept request with /a %u\", num_requests);\n    new_lines(numchar);\n    memcpy(pending_requests[num_requests].id, public_key, TOX_PUBLIC_KEY_SIZE);\n    pending_requests[num_requests].accepted = 0;\n    ++num_requests;\n    do_refresh();\n}\n\nvoid print_message(Tox *m, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,\n                   void *userdata)\n{\n    /* ensure null termination */\n    uint8_t null_string[length + 1];\n    memcpy(null_string, string, length);\n    null_string[length] = 0;\n    print_formatted_message(m, (char *)null_string, friendnumber, 0);\n}\n\nvoid print_nickchange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)\n{\n    char name[TOX_MAX_NAME_LENGTH + 1];\n\n    if (getfriendname_terminated(m, friendnumber, name) != -1) {\n        char msg[100 + length];\n\n        if (name[0] != 0)\n            sprintf(msg, \"[i] [%d] %s is now known as %s.\", friendnumber, name, string);\n        else\n            sprintf(msg, \"[i] [%d] Friend's name is %s.\", friendnumber, string);\n\n        new_lines(msg);\n    }\n}\n\nvoid print_statuschange(Tox *m, uint32_t friendnumber, const uint8_t *string, size_t length, void *userdata)\n{\n    char name[TOX_MAX_NAME_LENGTH + 1];\n\n    if (getfriendname_terminated(m, friendnumber, name) != -1) {\n        char msg[100 + length + strlen(name) + 1];\n\n        if (name[0] != 0)\n            sprintf(msg, \"[i] [%d] %s's status changed to %s.\", friendnumber, name, string);\n        else\n            sprintf(msg, \"[i] [%d] Their status changed to %s.\", friendnumber, string);\n\n        new_lines(msg);\n    }\n}\n\nstatic char *data_file_name = NULL;\n\nstatic Tox *load_data()\n{\n    FILE *data_file = fopen(data_file_name, \"r\");\n\n    if (data_file) {\n        fseek(data_file, 0, SEEK_END);\n        size_t size = ftell(data_file);\n        rewind(data_file);\n\n        uint8_t data[size];\n\n        if (fread(data, sizeof(uint8_t), size, data_file) != size) {\n            fputs(\"[!] could not read data file!\\n\", stderr);\n            fclose(data_file);\n            return 0;\n        }\n\n        struct Tox_Options options;\n\n        tox_options_default(&options);\n\n        options.savedata_type = TOX_SAVEDATA_TYPE_TOX_SAVE;\n\n        options.savedata_data = data;\n\n        options.savedata_length = size;\n\n        Tox *m = tox_new(&options, NULL);\n\n        if (fclose(data_file) < 0) {\n            perror(\"[!] fclose failed\");\n            /* we got it open and the expected data read... let it be ok */\n            /* return 0; */\n        }\n\n        return m;\n    }\n\n    return tox_new(NULL, NULL);\n}\n\nstatic int save_data(Tox *m)\n{\n    FILE *data_file = fopen(data_file_name, \"w\");\n\n    if (!data_file) {\n        perror(\"[!] load_key\");\n        return 0;\n    }\n\n    int res = 1;\n    size_t size = tox_get_savedata_size(m);\n    uint8_t data[size];\n    tox_get_savedata(m, data);\n\n    if (fwrite(data, sizeof(uint8_t), size, data_file) != size) {\n        fputs(\"[!] could not write data file (1)!\", stderr);\n        res = 0;\n    }\n\n    if (fclose(data_file) < 0) {\n        perror(\"[!] could not write data file (2)\");\n        res = 0;\n    }\n\n    return res;\n}\n\nstatic int save_data_file(Tox *m, char *path)\n{\n    data_file_name = path;\n\n    if (save_data(m))\n        return 1;\n\n    return 0;\n}\n\nvoid print_help(char *prog_name)\n{\n    printf(\"nTox %.1f - Command-line tox-core client\\n\", 0.1);\n    printf(\"Usage: %s [--ipv4|--ipv6] IP PORT KEY [-f keyfile]\\n\", prog_name);\n\n    puts(\"Options: (order IS relevant)\");\n    puts(\"  --ipv4 / --ipv6 [Optional] Support IPv4 only or IPv4 & IPv6.\");\n    puts(\"  IP PORT KEY     [REQUIRED] A node to connect to (IP/Port) and its key.\");\n    puts(\"  -f keyfile      [Optional] Specify a keyfile to read from and write to.\");\n}\n\nvoid print_invite(Tox *m, int friendnumber, uint8_t type, const uint8_t *data, uint16_t length, void *userdata)\n{\n    char msg[256];\n\n    if (type == TOX_GROUPCHAT_TYPE_TEXT) {\n        sprintf(msg, \"[i] received group chat invite from: %u, auto accepting and joining. group number: %u\", friendnumber,\n                tox_join_groupchat(m, friendnumber, data, length));\n    } else {\n        sprintf(msg, \"[i] Group chat invite received of type %u that could not be accepted by ntox.\", type);\n    }\n\n    new_lines(msg);\n}\n\nvoid print_groupchatpeers(Tox *m, int groupnumber)\n{\n    int num = tox_group_number_peers(m, groupnumber);\n\n    if (num < 0)\n        return;\n\n    if (!num) {\n        new_lines(\"[g]+ no peers left in group.\");\n        return;\n    }\n\n    uint8_t names[num][TOX_MAX_NAME_LENGTH];\n    uint16_t lengths[num];\n    tox_group_get_names(m, groupnumber, names, lengths, num);\n    int i;\n    char numstr[16];\n    char header[] = \"[g]+ \";\n    size_t header_len = strlen(header);\n    char msg[STRING_LENGTH];\n    strcpy(msg, header);\n    size_t len_total = header_len;\n\n    for (i = 0; i < num; ++i) {\n        size_t len_name = lengths[i];\n        size_t len_num = sprintf(numstr, \"%i: \", i);\n\n        if (len_num + len_name + len_total + 3 >= STRING_LENGTH) {\n            new_lines_mark(msg, 1);\n\n            strcpy(msg, header);\n            len_total = header_len;\n        }\n\n        strcpy(msg + len_total, numstr);\n        len_total += len_num;\n        memcpy(msg + len_total, (char *)names[i], len_name);\n        len_total += len_name;\n\n        if (i < num - 1) {\n            strcpy(msg + len_total, \"|\");\n            len_total++;\n        }\n    }\n\n    new_lines_mark(msg, 1);\n}\n\nvoid print_groupmessage(Tox *m, int groupnumber, int peernumber, const uint8_t *message, uint16_t length,\n                        void *userdata)\n{\n    char msg[256 + length];\n    uint8_t name[TOX_MAX_NAME_LENGTH] = {0};\n    int len = tox_group_peername(m, groupnumber, peernumber, name);\n\n    //print_groupchatpeers(m, groupnumber);\n    if (len <= 0)\n        name[0] = 0;\n\n    if (name[0] != 0)\n        sprintf(msg, \"[g] %u: %u <%s>: %s\", groupnumber, peernumber, name, message);\n    else\n        sprintf(msg, \"[g] #%u: %u Unknown: %s\", groupnumber, peernumber, message);\n\n    new_lines(msg);\n}\nvoid print_groupnamelistchange(Tox *m, int groupnumber, int peernumber, uint8_t change, void *userdata)\n{\n    char msg[256];\n\n    if (change == TOX_CHAT_CHANGE_PEER_ADD) {\n        sprintf(msg, \"[g] #%i: New peer %i.\", groupnumber, peernumber);\n        new_lines(msg);\n    } else if (change == TOX_CHAT_CHANGE_PEER_DEL) {\n        /* if peer was the last in list, it simply dropped,\n         * otherwise it was overwritten by the last peer\n         *\n         * adjust output\n         */\n        int peers_total = tox_group_number_peers(m, groupnumber);\n\n        if (peers_total == peernumber) {\n            sprintf(msg, \"[g] #%i: Peer %i left.\", groupnumber, peernumber);\n            new_lines(msg);\n        } else {\n            uint8_t peername[TOX_MAX_NAME_LENGTH] = {0};\n            int len = tox_group_peername(m, groupnumber, peernumber, peername);\n\n            if (len <= 0)\n                peername[0] = 0;\n\n            sprintf(msg, \"[g] #%i: Peer %i left. Former peer [%i: <%s>] is now peer %i.\", groupnumber, peernumber,\n                    peers_total, peername, peernumber);\n            new_lines(msg);\n        }\n    } else if (change == TOX_CHAT_CHANGE_PEER_NAME) {\n        uint8_t peername[TOX_MAX_NAME_LENGTH] = {0};\n        int len = tox_group_peername(m, groupnumber, peernumber, peername);\n\n        if (len <= 0)\n            peername[0] = 0;\n\n        sprintf(msg, \"[g] #%i: Peer %i's name changed: %s\", groupnumber, peernumber, peername);\n        new_lines(msg);\n    } else {\n        sprintf(msg, \"[g] #%i: Name list changed (peer %i, change %i?):\", groupnumber, peernumber, change);\n        new_lines(msg);\n        print_groupchatpeers(m, groupnumber);\n    }\n}\nvoid file_request_accept(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t type, uint64_t file_size,\n                         const uint8_t *filename, size_t filename_length, void *user_data)\n{\n    if (type != TOX_FILE_KIND_DATA) {\n        new_lines(\"Refused invalid file type.\");\n        tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, 0);\n        return;\n    }\n\n    char msg[512];\n    sprintf(msg, \"[t] %u is sending us: %s of size %llu\", friend_number, filename, (long long unsigned int)file_size);\n    new_lines(msg);\n\n    if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, 0)) {\n        sprintf(msg, \"Accepted file transfer. (saving file as: %u.%u.bin)\", friend_number, file_number);\n        new_lines(msg);\n    } else\n        new_lines(\"Could not accept file transfer.\");\n}\n\nvoid file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,\n                        void *user_data)\n{\n    char msg[512] = {0};\n    sprintf(msg, \"[t] control %u received\", control);\n    new_lines(msg);\n\n    if (control == TOX_FILE_CONTROL_CANCEL) {\n        unsigned int i;\n\n        for (i = 0; i < NUM_FILE_SENDERS; ++i) {\n            /* This is slow */\n            if (file_senders[i].file && file_senders[i].friendnum == friend_number && file_senders[i].filenumber == file_number) {\n                fclose(file_senders[i].file);\n                file_senders[i].file = 0;\n                char msg[512];\n                sprintf(msg, \"[t] %u file transfer: %u cancelled\", file_senders[i].friendnum, file_senders[i].filenumber);\n                new_lines(msg);\n            }\n        }\n    }\n}\n\nvoid write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,\n                size_t length, void *user_data)\n{\n    if (length == 0) {\n        char msg[512];\n        sprintf(msg, \"[t] %u file transfer: %u completed\", friendnumber, filenumber);\n        new_lines(msg);\n        return;\n    }\n\n    char filename[256];\n    sprintf(filename, \"%u.%u.bin\", friendnumber, filenumber);\n    FILE *pFile = fopen(filename, \"r+b\");\n\n    if (pFile == NULL)\n        pFile = fopen(filename, \"wb\");\n\n    fseek(pFile, position, SEEK_SET);\n\n    if (fwrite(data, length, 1, pFile) != 1)\n        new_lines(\"Error writing to file\");\n\n    fclose(pFile);\n}\n\nvoid print_online(Tox *tox, uint32_t friendnumber, TOX_CONNECTION status, void *userdata)\n{\n    if (status)\n        printf(\"\\nOther went online.\\n\");\n    else {\n        printf(\"\\nOther went offline.\\n\");\n        unsigned int i;\n\n        for (i = 0; i < NUM_FILE_SENDERS; ++i)\n            if (file_senders[i].file != 0 && file_senders[i].friendnum == friendnumber) {\n                fclose(file_senders[i].file);\n                file_senders[i].file = 0;\n            }\n    }\n}\n\nchar timeout_getch(Tox *m)\n{\n    char c;\n    int slpval = tox_iteration_interval(m);\n\n    fd_set fds;\n    FD_ZERO(&fds);\n    FD_SET(0, &fds);\n    struct timeval tv;\n    tv.tv_sec = 0;\n    tv.tv_usec = slpval * 1000;\n\n    c = ERR;\n    int n = select(1, &fds, NULL, NULL, &tv);\n\n    if (n < 0) {\n        new_lines(\"select error: maybe interupted\");\n    } else if (n == 0) {\n    } else {\n        c = getch();\n    }\n\n    return c;\n}\n\nint main(int argc, char *argv[])\n{\n    /* minimalistic locale support (i.e. when printing dates) */\n    setlocale(LC_ALL, \"\");\n\n    if (argc < 4) {\n        if ((argc == 2) && !strcmp(argv[1], \"-h\")) {\n            print_help(argv[0]);\n            exit(0);\n        }\n\n        printf(\"Usage: %s [--ipv4|--ipv6] IP PORT KEY [-f keyfile] (or %s -h for help)\\n\", argv[0], argv[0]);\n        exit(0);\n    }\n\n    /* let user override default by cmdline */\n    uint8_t ipv6enabled = 1; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    int on = 0;\n    char *filename = \"data\";\n    char idstring[200] = {0};\n    Tox *m;\n\n    /* [-f keyfile] MUST be last two arguments, no point in walking over the list\n     * especially not a good idea to accept it anywhere in the middle */\n    if (argc > argvoffset + 3)\n        if (!strcmp(argv[argc - 2], \"-f\"))\n            filename = argv[argc - 1];\n\n    data_file_name = filename;\n    m = load_data();\n\n    if ( !m ) {\n        fputs(\"Failed to allocate Messenger datastructure\", stderr);\n        exit(0);\n    }\n\n    save_data_file(m, filename);\n\n    tox_callback_friend_request(m, print_request, NULL);\n    tox_callback_friend_message(m, print_message, NULL);\n    tox_callback_friend_name(m, print_nickchange, NULL);\n    tox_callback_friend_status_message(m, print_statuschange, NULL);\n    tox_callback_group_invite(m, print_invite, NULL);\n    tox_callback_group_message(m, print_groupmessage, NULL);\n    tox_callback_file_recv_chunk(m, write_file, NULL);\n    tox_callback_file_recv_control(m, file_print_control, NULL);\n    tox_callback_file_recv(m, file_request_accept, NULL);\n    tox_callback_file_chunk_request(m, tox_file_chunk_request, NULL);\n    tox_callback_group_namelist_change(m, print_groupnamelistchange, NULL);\n    tox_callback_friend_connection_status(m, print_online, NULL);\n\n    initscr();\n    noecho();\n    raw();\n    getmaxyx(stdscr, y, x);\n\n    new_lines(\"/h for list of commands\");\n    get_id(m, idstring);\n    new_lines(idstring);\n    strcpy(input_line, \"\");\n\n    uint16_t port = atoi(argv[argvoffset + 2]);\n    unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);\n    int res = tox_bootstrap(m, argv[argvoffset + 1], port, binary_string, NULL);\n\n    if (!res) {\n        printf(\"Failed to convert \\\"%s\\\" into an IP address. Exiting...\\n\", argv[argvoffset + 1]);\n        endwin();\n        exit(1);\n    }\n\n    nodelay(stdscr, TRUE);\n\n    new_lines(\"[i] change username with /n\");\n    uint8_t name[TOX_MAX_NAME_LENGTH + 1];\n    tox_self_get_name(m, name);\n    uint16_t namelen = tox_self_get_name_size(m);\n    name[namelen] = 0;\n\n    if (namelen > 0) {\n        char whoami[128 + TOX_MAX_NAME_LENGTH];\n        snprintf(whoami, sizeof(whoami), \"[i] your current username is: %s\", name);\n        new_lines(whoami);\n    }\n\n    time_t timestamp0 = time(NULL);\n\n    while (1) {\n        if (on == 0) {\n            if (tox_self_get_connection_status(m)) {\n                new_lines(\"[i] connected to DHT\");\n                on = 1;\n            } else {\n                time_t timestamp1 = time(NULL);\n\n                if (timestamp0 + 10 < timestamp1) {\n                    timestamp0 = timestamp1;\n                    tox_bootstrap(m, argv[argvoffset + 1], port, binary_string, NULL);\n                }\n            }\n        }\n\n        tox_iterate(m);\n        do_refresh();\n\n        int c = timeout_getch(m);\n\n        if (c == ERR || c == 27)\n            continue;\n\n        getmaxyx(stdscr, y, x);\n\n        if ((c == 0x0d) || (c == 0x0a)) {\n            line_eval(m, input_line);\n            strcpy(input_line, \"\");\n        } else if (c == 8 || c == 127) {\n            input_line[strlen(input_line) - 1] = '\\0';\n        } else if (isalnum(c) || ispunct(c) || c == ' ') {\n            appender(input_line, (char) c);\n        }\n    }\n\n    free(binary_string);\n    save_data_file(m, filename);\n    tox_kill(m);\n    endwin();\n    return 0;\n}\n"
  },
  {
    "path": "testing/nTox.h",
    "content": "/* nTox.h\n *\n *Textual frontend for Tox.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef NTOX_H\n#define NTOX_H\n\n/*\n * module actually exports nothing for the outside\n */\n\n#include <ctype.h>\n#include <curses.h>\n\n#include \"../toxcore/tox.h\"\n\n#define STRING_LENGTH 256\n#define HISTORY 50\n\nvoid new_lines(char *line);\nvoid do_refresh();\n\n#endif\n"
  },
  {
    "path": "testing/tox_shell.c",
    "content": "/* Tox Shell\n *\n * Proof of concept ssh like server software using tox.\n *\n * Command line arguments are the ip, port and public_key of a node (for bootstrapping).\n *\n * EX: ./test 127.0.0.1 33445 CDCFD319CE3460824B33BE58FD86B8941C9585181D8FBD7C79C5721D7C2E9F7C\n *\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/tox.h\"\n#include \"misc_tools.c\"\n\n#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)\n#include <util.h>\n#elif defined(__FreeBSD__) || defined(__DragonFly__)\n#include <libutil.h>\n#else\n#include <pty.h>\n#endif\n#include <unistd.h>\n#include <fcntl.h>\n\n#define c_sleep(x) usleep(1000*x)\n\nvoid print_online(Tox *tox, uint32_t friendnumber, TOX_CONNECTION status, void *userdata)\n{\n    if (status)\n        printf(\"\\nOther went online.\\n\");\n    else\n        printf(\"\\nOther went offline.\\n\");\n}\n\nvoid print_message(Tox *tox, uint32_t friendnumber, TOX_MESSAGE_TYPE type, const uint8_t *string, size_t length,\n                   void *userdata)\n{\n    int master = *((int *)userdata);\n    write(master, string, length);\n    write(master, \"\\n\", 1);\n}\n\nint main(int argc, char *argv[])\n{\n    uint8_t ipv6enabled = 1; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    /* with optional --ipvx, now it can be 1-4 arguments... */\n    if ((argc != argvoffset + 2) && (argc != argvoffset + 4)) {\n        printf(\"Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node)\\n\", argv[0]);\n        exit(0);\n    }\n\n    int *master = malloc(sizeof(int));\n    int ret = forkpty(master, NULL, NULL, NULL);\n\n    if (ret == -1) {\n        printf(\"fork failed\\n\");\n        return 1;\n    }\n\n    if (ret == 0) {\n        execl(\"/bin/sh\", \"sh\", NULL);\n        return 0;\n    }\n\n    int flags = fcntl(*master, F_GETFL, 0);\n    int r = fcntl(*master, F_SETFL, flags | O_NONBLOCK);\n\n    if (r < 0) {\n        printf(\"error setting flags\\n\");\n    }\n\n    Tox *tox = tox_new(0, 0);\n    tox_callback_friend_connection_status(tox, print_online, NULL);\n    tox_callback_friend_message(tox, print_message, master);\n\n\n    uint16_t port = atoi(argv[argvoffset + 2]);\n    unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);\n    int res = tox_bootstrap(tox, argv[argvoffset + 1], port, binary_string, 0);\n    free(binary_string);\n\n    if (!res) {\n        printf(\"Failed to convert \\\"%s\\\" into an IP address. Exiting...\\n\", argv[argvoffset + 1]);\n        exit(1);\n    }\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox, address);\n    uint32_t i;\n\n    for (i = 0; i < TOX_ADDRESS_SIZE; i++) {\n        printf(\"%02X\", address[i]);\n    }\n\n    char temp_id[128];\n    printf(\"\\nEnter the address of the other id you want to sync with (38 bytes HEX format):\\n\");\n\n    if (scanf(\"%s\", temp_id) != 1) {\n        return 1;\n    }\n\n    uint8_t *bin_id = hex_string_to_bin(temp_id);\n    uint32_t num = tox_friend_add(tox, bin_id, (uint8_t *)\"Install Gentoo\", sizeof(\"Install Gentoo\"), 0);\n    free(bin_id);\n\n    if (num == UINT32_MAX) {\n        printf(\"\\nSomething went wrong when adding friend.\\n\");\n        return 1;\n    }\n\n    uint8_t notconnected = 1;\n\n    while (1) {\n        if (tox_self_get_connection_status(tox) && notconnected) {\n            printf(\"\\nDHT connected.\\n\");\n            notconnected = 0;\n        }\n\n        while (tox_friend_get_connection_status(tox, num, 0)) {\n            uint8_t buf[TOX_MAX_MESSAGE_LENGTH];\n            ret = read(*master, buf, sizeof(buf));\n\n            if (ret <= 0)\n                break;\n\n            tox_friend_send_message(tox, num, TOX_MESSAGE_TYPE_NORMAL, buf, ret, 0);\n        }\n\n        tox_iterate(tox);\n        c_sleep(1);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "testing/tox_sync.c",
    "content": "/* Tox Sync\n *\n * Proof of concept bittorrent sync like software using tox, syncs two directories.\n *\n * Command line arguments are the ip, port and public_key of a node (for bootstrapping) and the folder to sync.\n *\n * EX: ./test 127.0.0.1 33445 CDCFD319CE3460824B33BE58FD86B8941C9585181D8FBD7C79C5721D7C2E9F7C ./sync_folder/\n *\n * NOTE: for security purposes, both tox sync instances must manually add each other as friend for it to work.\n *\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/tox.h\"\n#include \"misc_tools.c\"\n\n#include <unistd.h>\n#define c_sleep(x) usleep(1000*x)\n\n#include <dirent.h>\n#include <stdio.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n\n#define NUM_FILE_SENDERS 256\ntypedef struct {\n    FILE *file;\n    uint32_t friendnum;\n    uint32_t filenumber;\n} File_t;\nFile_t file_senders[NUM_FILE_SENDERS];\nFile_t file_recv[NUM_FILE_SENDERS];\nuint8_t numfilesenders;\n\nvoid tox_file_chunk_request(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length,\n                            void *user_data)\n{\n    unsigned int i;\n\n    for (i = 0; i < NUM_FILE_SENDERS; ++i) {\n        /* This is slow */\n        if (file_senders[i].file && file_senders[i].friendnum == friend_number && file_senders[i].filenumber == file_number) {\n            if (length == 0) {\n                fclose(file_senders[i].file);\n                file_senders[i].file = 0;\n                printf(\"[t] %u file transfer: %u completed\\n\", file_senders[i].friendnum, file_senders[i].filenumber);\n                break;\n            }\n\n            fseek(file_senders[i].file, position, SEEK_SET);\n            uint8_t data[length];\n            int len = fread(data, 1, length, file_senders[i].file);\n            tox_file_send_chunk(tox, friend_number, file_number, position, data, len, 0);\n            break;\n        }\n    }\n}\n\n\nuint32_t add_filesender(Tox *m, uint16_t friendnum, char *filename)\n{\n    FILE *tempfile = fopen(filename, \"rb\");\n\n    if (tempfile == 0)\n        return -1;\n\n    fseek(tempfile, 0, SEEK_END);\n    uint64_t filesize = ftell(tempfile);\n    fseek(tempfile, 0, SEEK_SET);\n    uint32_t filenum = tox_file_send(m, friendnum, TOX_FILE_KIND_DATA, filesize, 0, (uint8_t *)filename,\n                                     strlen(filename), 0);\n\n    if (filenum == -1)\n        return -1;\n\n    file_senders[numfilesenders].file = tempfile;\n    file_senders[numfilesenders].friendnum = friendnum;\n    file_senders[numfilesenders].filenumber = filenum;\n    ++numfilesenders;\n    return filenum;\n}\n\nvoid kill_filesender(Tox *m, uint32_t filenum)\n{\n    uint32_t i;\n\n    for (i = 0; i < NUM_FILE_SENDERS; ++i)\n        if (file_senders[i].file != 0 && file_senders[i].filenumber == filenum) {\n            fclose(file_senders[i].file);\n            file_senders[i].file = 0;\n        }\n}\nint not_sending()\n{\n    uint32_t i;\n\n    for (i = 0; i < NUM_FILE_SENDERS; ++i)\n        if (file_senders[i].file != 0)\n            return 0;\n\n    return 1;\n}\n\nstatic char path[1024];\n\nvoid file_request_accept(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t type, uint64_t file_size,\n                         const uint8_t *filename, size_t filename_length, void *user_data)\n{\n    if (type != TOX_FILE_KIND_DATA) {\n        printf(\"Refused invalid file type.\");\n        tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, 0);\n        return;\n    }\n\n    char fullpath[1024];\n    uint32_t i;\n    uint16_t rm = 0;\n\n    for (i = 0; i < strlen((char *)filename); ++i) {\n        if (filename[i] == '/')\n            rm = i;\n    }\n\n    if (path[strlen(path) - 1] == '/')\n        sprintf(fullpath, \"%s%s\", path, filename + rm + 1);\n    else\n        sprintf(fullpath, \"%s/%s\", path, filename + rm + 1);\n\n    FILE *tempfile = fopen(fullpath, \"rb\");\n\n    if (tempfile != 0) {\n        fclose(tempfile);\n        tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, 0);\n        return;\n    }\n\n    uint8_t file_index = (file_number >> 16) - 1;\n    file_recv[file_index].file = fopen(fullpath, \"wb\");\n\n    if (file_recv[file_index].file == 0) {\n        tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_CANCEL, 0);\n        return;\n    }\n\n    if (tox_file_control(tox, friend_number, file_number, TOX_FILE_CONTROL_RESUME, 0)) {\n        printf(\"Accepted file transfer. (file: %s)\\n\", fullpath);\n    }\n\n}\n\nvoid file_print_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,\n                        void *user_data)\n{\n    if (file_number < (1 << 15) && (control == TOX_FILE_CONTROL_CANCEL)) {\n        kill_filesender(tox, file_number);\n        return;\n    }\n\n    if (file_number > (1 << 15) && (control == TOX_FILE_CONTROL_CANCEL)) {\n        uint8_t file_index = (file_number >> 16) - 1;\n        fclose(file_recv[file_index].file);\n        printf(\"File closed\\n\");\n        file_recv[file_index].file = 0;\n        return;\n    }\n}\n\nvoid write_file(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,\n                size_t length, void *user_data)\n{\n    uint8_t file_index = (filenumber >> 16) - 1;\n\n    if (length == 0) {\n        fclose(file_recv[file_index].file);\n        printf(\"File closed\\n\");\n        file_recv[file_index].file = 0;\n        printf(\"%u file transfer: %u completed\\n\", friendnumber, filenumber);\n        return;\n    }\n\n    if (file_recv[file_index].file != 0) {\n        fseek(file_recv[file_index].file, position, SEEK_SET);\n\n        if (fwrite(data, length, 1, file_recv[file_index].file) != 1)\n            printf(\"Error writing data\\n\");\n    }\n}\n\nvoid print_online(Tox *tox, uint32_t friendnumber, TOX_CONNECTION status, void *userdata)\n{\n    if (status)\n        printf(\"\\nOther went online.\\n\");\n    else {\n        printf(\"\\nOther went offline.\\n\");\n        unsigned int i;\n\n        for (i = 0; i < NUM_FILE_SENDERS; ++i) {\n            if (file_senders[i].file != 0) {\n                fclose(file_senders[i].file);\n                file_senders[i].file = 0;\n            }\n\n            if (file_recv[i].file != 0) {\n                fclose(file_recv[i].file);\n                file_recv[i].file = 0;\n            }\n        }\n    }\n}\n\nint main(int argc, char *argv[])\n{\n    uint8_t ipv6enabled = 1; /* x */\n    int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);\n\n    if (argvoffset < 0)\n        exit(1);\n\n    /* with optional --ipvx, now it can be 1-4 arguments... */\n    if ((argc != argvoffset + 3) && (argc != argvoffset + 5)) {\n        printf(\"Usage: %s [--ipv4|--ipv6] ip port public_key (of the DHT bootstrap node) folder (to sync)\\n\", argv[0]);\n        exit(0);\n    }\n\n    Tox *tox = tox_new(0, 0);\n    tox_callback_file_recv_chunk(tox, write_file, NULL);\n    tox_callback_file_recv_control(tox, file_print_control, NULL);\n    tox_callback_file_recv(tox, file_request_accept, NULL);\n    tox_callback_file_chunk_request(tox, tox_file_chunk_request, NULL);\n    tox_callback_friend_connection_status(tox, print_online, NULL);\n\n    uint16_t port = atoi(argv[argvoffset + 2]);\n    unsigned char *binary_string = hex_string_to_bin(argv[argvoffset + 3]);\n    int res = tox_bootstrap(tox, argv[argvoffset + 1], port, binary_string, 0);\n    free(binary_string);\n\n    if (!res) {\n        printf(\"Failed to convert \\\"%s\\\" into an IP address. Exiting...\\n\", argv[argvoffset + 1]);\n        exit(1);\n    }\n\n    uint8_t address[TOX_ADDRESS_SIZE];\n    tox_self_get_address(tox, address);\n    uint32_t i;\n\n    for (i = 0; i < TOX_ADDRESS_SIZE; i++) {\n        printf(\"%02X\", address[i]);\n    }\n\n    char temp_id[128];\n    printf(\"\\nEnter the address of the other id you want to sync with (38 bytes HEX format):\\n\");\n\n    if (scanf(\"%s\", temp_id) != 1) {\n        return 1;\n    }\n\n    uint8_t *bin_id = hex_string_to_bin(temp_id);\n    uint32_t num = tox_friend_add(tox, bin_id, (uint8_t *)\"Install Gentoo\", sizeof(\"Install Gentoo\"), 0);\n    free(bin_id);\n\n    if (num == UINT32_MAX) {\n        printf(\"\\nSomething went wrong when adding friend.\\n\");\n        return 1;\n    }\n\n    memcpy(path, argv[argvoffset + 4], strlen(argv[argvoffset + 4]));\n    DIR           *d;\n    struct dirent *dir;\n    uint8_t notconnected = 1;\n\n    while (1) {\n        if (tox_self_get_connection_status(tox) && notconnected) {\n            printf(\"\\nDHT connected.\\n\");\n            notconnected = 0;\n        }\n\n        if (not_sending() && tox_friend_get_connection_status(tox, num, 0)) {\n            d = opendir(path);\n\n            if (d) {\n                while ((dir = readdir(d)) != NULL) {\n                    if (dir->d_type == DT_REG) {\n                        char fullpath[1024];\n\n                        if (path[strlen(path) - 1] == '/')\n                            sprintf(fullpath, \"%s%s\", path, dir->d_name);\n                        else\n                            sprintf(fullpath, \"%s/%s\", path, dir->d_name);\n\n                        add_filesender(tox, num, fullpath);\n                    }\n                }\n\n                closedir(d);\n\n            } else {\n                printf(\"\\nFailed to open directory.\\n\");\n                return 1;\n            }\n        }\n\n        tox_iterate(tox);\n        c_sleep(1);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tox.spec.in",
    "content": "Name:           @PACKAGE_NAME@\nVersion:        @VERSION@\nRelease:        1%{?dist}\nSummary:        All-in-one secure communication platform\n\nLicense:        GPLv3\nURL:            https://github.com/irungentoo/toxcore\nSource0:        https://github.com/irungentoo/toxcore/releases/tox-%{version}.tar.gz\n\nBuildRequires:  autoconf automake libtool libvpx-devel opus-devel\nBuildRequires:  libsodium-devel libconfig-devel\n\n%description\nWith 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.\n\n%package devel\nSummary:        Development files for @PACKAGE_NAME@\nRequires:       %{name} = %{version}-%{release}\n\n%description devel\nDevelopment package for @PACKAGE_NAME@\n\n%prep\n%setup -q\n\n\n%build\n%configure \\\n    --enable-shared \\\n    --disable-static \\\n    --enable-av \\\n    --disable-ntox \\\n    --disable-daemon \\\n    --disable-testing\n\nmake %{?_smp_mflags}\n\n\n%install\n%make_install\n\n# remove la files\nfind %{buildroot} -name '*.la' -delete -print\n\n# not handling DHT_bootstrap yet\nrm -f %{buildroot}%{_bindir}/DHT_bootstrap\n\n%post\n/sbin/ldconfig\n\n%postun\n/sbin/ldconfig\n\n%files\n%defattr(-,root,root)\n%doc COPYING README.md\n%{_libdir}/libtox*.so.*\n\n%files devel\n%defattr(-, root, root)\n%{_includedir}/tox/\n%{_libdir}/libtox*.so\n%{_libdir}/pkgconfig/libtox*.pc\n\n%changelog\n* Tue Mar  3 2015 Sergey 'Jin' Bostandzhyan <jin@mediatomb.cc> - 0.0.0-1\n- initial package\n"
  },
  {
    "path": "toxav/Makefile.inc",
    "content": "if BUILD_AV\n\nlib_LTLIBRARIES +=  libtoxav.la\n                    libtoxav_la_include_HEADERS = ../toxav/toxav.h\n                    libtoxav_la_includedir = $(includedir)/tox\n\nlibtoxav_la_SOURCES = ../toxav/rtp.h \\\n                    ../toxav/rtp.c \\\n                    ../toxav/msi.h \\\n                    ../toxav/msi.c \\\n                    ../toxav/group.h \\\n                    ../toxav/group.c \\\n                    ../toxav/audio.h \\\n                    ../toxav/audio.c \\\n                    ../toxav/video.h \\\n                    ../toxav/video.c \\\n                    ../toxav/bwcontroller.h \\\n                    ../toxav/bwcontroller.c \\\n                    ../toxav/toxav.h \\\n                    ../toxav/toxav.c \\\n                    ../toxav/toxav_old.c\n\nlibtoxav_la_CFLAGS = -I../toxcore \\\n                    -I../toxav \\\n                    $(LIBSODIUM_CFLAGS) \\\n                    $(NACL_CFLAGS) \\\n                    $(AV_CFLAGS) \\\n                    $(PTHREAD_CFLAGS)\n\nlibtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \\\n                    $(LIBSODIUM_LDFLAGS) \\\n                    $(NACL_LDFLAGS) \\\n                    $(EXTRA_LT_LDFLAGS) \\\n                    $(WINSOCK2_LIBS)\n\nlibtoxav_la_LIBADD =  libtoxcore.la \\\n                    $(LIBSODIUM_LIBS) \\\n                    $(NACL_LIBS) \\\n                    $(PTHREAD_LIBS) \\\n                    $(AV_LIBS)\n\nendif"
  },
  {
    "path": "toxav/audio.c",
    "content": "/**  audio.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include <stdlib.h>\n\n#include \"audio.h\"\n#include \"rtp.h\"\n\n#include \"../toxcore/logger.h\"\n\nstatic struct JitterBuffer *jbuf_new(uint32_t capacity);\nstatic void jbuf_clear(struct JitterBuffer *q);\nstatic void jbuf_free(struct JitterBuffer *q);\nstatic int jbuf_write(struct JitterBuffer *q, struct RTPMessage *m);\nstatic struct RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);\nOpusEncoder *create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count);\nbool reconfigure_audio_encoder(OpusEncoder **e, int32_t new_br, int32_t new_sr, uint8_t new_ch,\n                               int32_t *old_br, int32_t *old_sr, int32_t *old_ch);\nbool reconfigure_audio_decoder(ACSession *ac, int32_t sampling_rate, int8_t channels);\n\n\n\nACSession *ac_new(ToxAV *av, uint32_t friend_number, toxav_audio_receive_frame_cb *cb, void *cb_data)\n{\n    ACSession *ac = calloc(sizeof(ACSession), 1);\n\n    if (!ac) {\n        LOGGER_WARNING(\"Allocation failed! Application might misbehave!\");\n        return NULL;\n    }\n\n    if (create_recursive_mutex(ac->queue_mutex) != 0) {\n        LOGGER_WARNING(\"Failed to create recursive mutex!\");\n        free(ac);\n        return NULL;\n    }\n\n    int status;\n    ac->decoder = opus_decoder_create(48000, 2, &status);\n\n    if (status != OPUS_OK) {\n        LOGGER_ERROR(\"Error while starting audio decoder: %s\", opus_strerror(status));\n        goto BASE_CLEANUP;\n    }\n\n    if (!(ac->j_buf = jbuf_new(3))) {\n        LOGGER_WARNING(\"Jitter buffer creaton failed!\");\n        opus_decoder_destroy(ac->decoder);\n        goto BASE_CLEANUP;\n    }\n\n    /* Initialize encoders with default values */\n    ac->encoder = create_audio_encoder(48000, 48000, 2);\n\n    if (ac->encoder == NULL)\n        goto DECODER_CLEANUP;\n\n    ac->le_bit_rate = 48000;\n    ac->le_sample_rate = 48000;\n    ac->le_channel_count = 2;\n\n    ac->ld_channel_count = 2;\n    ac->ld_sample_rate = 48000;\n    ac->ldrts = 0; /* Make it possible to reconfigure straight away */\n\n    /* These need to be set in order to properly\n     * do error correction with opus */\n    ac->lp_frame_duration = 120;\n    ac->lp_sampling_rate = 48000;\n    ac->lp_channel_count = 1;\n\n    ac->av = av;\n    ac->friend_number = friend_number;\n    ac->acb.first = cb;\n    ac->acb.second = cb_data;\n\n    return ac;\n\nDECODER_CLEANUP:\n    opus_decoder_destroy(ac->decoder);\n    jbuf_free(ac->j_buf);\nBASE_CLEANUP:\n    pthread_mutex_destroy(ac->queue_mutex);\n    free(ac);\n    return NULL;\n}\nvoid ac_kill(ACSession *ac)\n{\n    if (!ac)\n        return;\n\n    opus_encoder_destroy(ac->encoder);\n    opus_decoder_destroy(ac->decoder);\n    jbuf_free(ac->j_buf);\n\n    pthread_mutex_destroy(ac->queue_mutex);\n\n    LOGGER_DEBUG(\"Terminated audio handler: %p\", ac);\n    free(ac);\n}\nvoid ac_iterate(ACSession *ac)\n{\n    if (!ac)\n        return;\n\n    /* TODO fix this and jitter buffering */\n\n    /* Enough space for the maximum frame size (120 ms 48 KHz stereo audio) */\n    int16_t tmp[5760 * 2];\n\n    struct RTPMessage *msg;\n    int rc = 0;\n\n    pthread_mutex_lock(ac->queue_mutex);\n\n    while ((msg = jbuf_read(ac->j_buf, &rc)) || rc == 2) {\n        pthread_mutex_unlock(ac->queue_mutex);\n\n        if (rc == 2) {\n            LOGGER_DEBUG(\"OPUS correction\");\n            int fs = (ac->lp_sampling_rate * ac->lp_frame_duration) / 1000;\n            rc = opus_decode(ac->decoder, NULL, 0, tmp, fs, 1);\n        } else {\n            /* Get values from packet and decode. */\n            /* NOTE: This didn't work very well\n            rc = convert_bw_to_sampling_rate(opus_packet_get_bandwidth(msg->data));\n            if (rc != -1) {\n                cs->last_packet_sampling_rate = rc;\n            } else {\n                LOGGER_WARNING(\"Failed to load packet values!\");\n                rtp_free_msg(msg);\n                continue;\n            }*/\n\n\n            /* Pick up sampling rate from packet */\n            memcpy(&ac->lp_sampling_rate, msg->data, 4);\n            ac->lp_sampling_rate = ntohl(ac->lp_sampling_rate);\n\n            ac->lp_channel_count = opus_packet_get_nb_channels(msg->data + 4);\n\n            /** NOTE: even though OPUS supports decoding mono frames with stereo decoder and vice versa,\n              * it didn't work quite well.\n              */\n            if (!reconfigure_audio_decoder(ac, ac->lp_sampling_rate, ac->lp_channel_count)) {\n                LOGGER_WARNING(\"Failed to reconfigure decoder!\");\n                free(msg);\n                continue;\n            }\n\n            rc = opus_decode(ac->decoder, msg->data + 4, msg->len - 4, tmp, 5760, 0);\n            free(msg);\n        }\n\n        if (rc < 0) {\n            LOGGER_WARNING(\"Decoding error: %s\", opus_strerror(rc));\n        } else if (ac->acb.first) {\n            ac->lp_frame_duration = (rc * 1000) / ac->lp_sampling_rate;\n\n            ac->acb.first(ac->av, ac->friend_number, tmp, rc, ac->lp_channel_count,\n                          ac->lp_sampling_rate, ac->acb.second);\n        }\n\n        return;\n    }\n\n    pthread_mutex_unlock(ac->queue_mutex);\n}\nint ac_queue_message(void *acp, struct RTPMessage *msg)\n{\n    if (!acp || !msg)\n        return -1;\n\n    if ((msg->header.pt & 0x7f) == (rtp_TypeAudio + 2) % 128) {\n        LOGGER_WARNING(\"Got dummy!\");\n        free(msg);\n        return 0;\n    }\n\n    if ((msg->header.pt & 0x7f) != rtp_TypeAudio % 128) {\n        LOGGER_WARNING(\"Invalid payload type!\");\n        free(msg);\n        return -1;\n    }\n\n    ACSession *ac = acp;\n\n    pthread_mutex_lock(ac->queue_mutex);\n    int rc = jbuf_write(ac->j_buf, msg);\n    pthread_mutex_unlock(ac->queue_mutex);\n\n    if (rc == -1) {\n        LOGGER_WARNING(\"Could not queue the message!\");\n        free(msg);\n        return -1;\n    }\n\n    return 0;\n}\nint ac_reconfigure_encoder(ACSession *ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels)\n{\n    if (!ac || !reconfigure_audio_encoder(&ac->encoder, bit_rate,\n                                          sampling_rate, channels,\n                                          &ac->le_bit_rate,\n                                          &ac->le_sample_rate,\n                                          &ac->le_channel_count))\n        return -1;\n\n    return 0;\n}\n\n\n\nstruct JitterBuffer {\n    struct RTPMessage **queue;\n    uint32_t size;\n    uint32_t capacity;\n    uint16_t bottom;\n    uint16_t top;\n};\n\nstatic struct JitterBuffer *jbuf_new(uint32_t capacity)\n{\n    unsigned int size = 1;\n\n    while (size <= (capacity * 4)) {\n        size *= 2;\n    }\n\n    struct JitterBuffer *q;\n\n    if (!(q = calloc(sizeof(struct JitterBuffer), 1))) return NULL;\n\n    if (!(q->queue = calloc(sizeof(struct RTPMessage *), size))) {\n        free(q);\n        return NULL;\n    }\n\n    q->size = size;\n    q->capacity = capacity;\n    return q;\n}\nstatic void jbuf_clear(struct JitterBuffer *q)\n{\n    for (; q->bottom != q->top; ++q->bottom) {\n        if (q->queue[q->bottom % q->size]) {\n            free(q->queue[q->bottom % q->size]);\n            q->queue[q->bottom % q->size] = NULL;\n        }\n    }\n}\nstatic void jbuf_free(struct JitterBuffer *q)\n{\n    if (!q) return;\n\n    jbuf_clear(q);\n    free(q->queue);\n    free(q);\n}\nstatic int jbuf_write(struct JitterBuffer *q, struct RTPMessage *m)\n{\n    uint16_t sequnum = m->header.sequnum;\n\n    unsigned int num = sequnum % q->size;\n\n    if ((uint32_t)(sequnum - q->bottom) > q->size) {\n        LOGGER_DEBUG(\"Clearing filled jitter buffer: %p\", q);\n\n        jbuf_clear(q);\n        q->bottom = sequnum - q->capacity;\n        q->queue[num] = m;\n        q->top = sequnum + 1;\n        return 0;\n    }\n\n    if (q->queue[num])\n        return -1;\n\n    q->queue[num] = m;\n\n    if ((sequnum - q->bottom) >= (q->top - q->bottom))\n        q->top = sequnum + 1;\n\n    return 0;\n}\nstatic struct RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success)\n{\n    if (q->top == q->bottom) {\n        *success = 0;\n        return NULL;\n    }\n\n    unsigned int num = q->bottom % q->size;\n\n    if (q->queue[num]) {\n        struct RTPMessage *ret = q->queue[num];\n        q->queue[num] = NULL;\n        ++q->bottom;\n        *success = 1;\n        return ret;\n    }\n\n    if ((uint32_t)(q->top - q->bottom) > q->capacity) {\n        ++q->bottom;\n        *success = 2;\n        return NULL;\n    }\n\n    *success = 0;\n    return NULL;\n}\nOpusEncoder *create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count)\n{\n    int status = OPUS_OK;\n    OpusEncoder *rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_VOIP, &status);\n\n    if (status != OPUS_OK) {\n        LOGGER_ERROR(\"Error while starting audio encoder: %s\", opus_strerror(status));\n        return NULL;\n    }\n\n    status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bit_rate));\n\n    if (status != OPUS_OK) {\n        LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(status));\n        goto FAILURE;\n    }\n\n    /* Enable in-band forward error correction in codec */\n    status = opus_encoder_ctl(rc, OPUS_SET_INBAND_FEC(1));\n\n    if (status != OPUS_OK) {\n        LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(status));\n        goto FAILURE;\n    }\n\n    /* Make codec resistant to up to 10% packet loss\n     * NOTE This could also be adjusted on the fly, rather than hard-coded,\n     *      with feedback from the receiving client.\n     */\n    status = opus_encoder_ctl(rc, OPUS_SET_PACKET_LOSS_PERC(10));\n\n    if (status != OPUS_OK) {\n        LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(status));\n        goto FAILURE;\n    }\n\n    /* Set algorithm to the highest complexity, maximizing compression */\n    status = opus_encoder_ctl(rc, OPUS_SET_COMPLEXITY(10));\n\n    if (status != OPUS_OK) {\n        LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(status));\n        goto FAILURE;\n    }\n\n    return rc;\n\nFAILURE:\n    opus_encoder_destroy(rc);\n    return NULL;\n}\nbool reconfigure_audio_encoder(OpusEncoder **e, int32_t new_br, int32_t new_sr, uint8_t new_ch,\n                               int32_t *old_br, int32_t *old_sr, int32_t *old_ch)\n{\n    /* Values are checked in toxav.c */\n    if (*old_sr != new_sr || *old_ch != new_ch) {\n        OpusEncoder *new_encoder = create_audio_encoder(new_br, new_sr, new_ch);\n\n        if (new_encoder == NULL)\n            return false;\n\n        opus_encoder_destroy(*e);\n        *e = new_encoder;\n    } else if (*old_br == new_br)\n        return true; /* Nothing changed */\n    else {\n        int status = opus_encoder_ctl(*e, OPUS_SET_BITRATE(new_br));\n\n        if (status != OPUS_OK) {\n            LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(status));\n            return false;\n        }\n    }\n\n    *old_br = new_br;\n    *old_sr = new_sr;\n    *old_ch = new_ch;\n\n    LOGGER_DEBUG (\"Reconfigured audio encoder br: %d sr: %d cc:%d\", new_br, new_sr, new_ch);\n    return true;\n}\nbool reconfigure_audio_decoder(ACSession *ac, int32_t sampling_rate, int8_t channels)\n{\n    if (sampling_rate != ac->ld_sample_rate || channels != ac->ld_channel_count) {\n        if (current_time_monotonic() - ac->ldrts < 500)\n            return false;\n\n        int status;\n        OpusDecoder *new_dec = opus_decoder_create(sampling_rate, channels, &status);\n\n        if (status != OPUS_OK) {\n            LOGGER_ERROR(\"Error while starting audio decoder(%d %d): %s\", sampling_rate, channels, opus_strerror(status));\n            return false;\n        }\n\n        ac->ld_sample_rate = sampling_rate;\n        ac->ld_channel_count = channels;\n        ac->ldrts = current_time_monotonic();\n\n        opus_decoder_destroy(ac->decoder);\n        ac->decoder = new_dec;\n\n        LOGGER_DEBUG(\"Reconfigured audio decoder sr: %d cc: %d\", sampling_rate, channels);\n    }\n\n    return true;\n}\n"
  },
  {
    "path": "toxav/audio.h",
    "content": "/**  audio.h\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef AUDIO_H\n#define AUDIO_H\n\n#include <opus.h>\n#include <pthread.h>\n\n#include \"toxav.h\"\n\n#include \"../toxcore/util.h\"\n\nstruct RTPMessage;\n\ntypedef struct ACSession_s {\n    /* encoding */\n    OpusEncoder *encoder;\n    int32_t le_sample_rate; /* Last encoder sample rate */\n    int32_t le_channel_count; /* Last encoder channel count */\n    int32_t le_bit_rate; /* Last encoder bit rate */\n\n    /* decoding */\n    OpusDecoder *decoder;\n    int32_t lp_channel_count; /* Last packet channel count */\n    int32_t lp_sampling_rate; /* Last packet sample rate */\n    int32_t lp_frame_duration; /* Last packet frame duration */\n    int32_t ld_sample_rate; /* Last decoder sample rate */\n    int32_t ld_channel_count; /* Last decoder channel count */\n    uint64_t ldrts; /* Last decoder reconfiguration time stamp */\n    void *j_buf;\n\n    pthread_mutex_t queue_mutex[1];\n\n    ToxAV *av;\n    uint32_t friend_number;\n    PAIR(toxav_audio_receive_frame_cb *, void *) acb; /* Audio frame receive callback */\n} ACSession;\n\nACSession *ac_new(ToxAV *av, uint32_t friend_number, toxav_audio_receive_frame_cb *cb, void *cb_data);\nvoid ac_kill(ACSession *ac);\nvoid ac_iterate(ACSession *ac);\nint ac_queue_message(void *acp, struct RTPMessage *msg);\nint ac_reconfigure_encoder(ACSession *ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels);\n\n#endif /* AUDIO_H */\n"
  },
  {
    "path": "toxav/bwcontroller.c",
    "content": "/**  bwcontroller.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include <assert.h>\n#include \"bwcontroller.h\"\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/util.h\"\n\n#define BWC_PACKET_ID 196\n#define BWC_SEND_INTERVAL_MS 1000\n#define BWC_REFRESH_INTERVAL_MS 10000\n#define BWC_AVG_PKT_COUNT 20\n\n/**\n *\n */\n\nstruct BWController_s {\n    void (*mcb) (BWController *, uint32_t, float, void *);\n    void *mcb_data;\n\n    Messenger *m;\n    uint32_t friend_number;\n\n    struct {\n        uint32_t lru; /* Last recv update time stamp */\n        uint32_t lsu; /* Last sent update time stamp */\n        uint32_t lfu; /* Last refresh time stamp */\n\n        uint32_t lost;\n        uint32_t recv;\n    } cycle;\n\n    struct {\n        uint32_t rb_s[BWC_AVG_PKT_COUNT];\n        RingBuffer *rb;\n    } rcvpkt; /* To calculate average received packet */\n};\n\nint bwc_handle_data(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object);\nvoid send_update(BWController *bwc);\n\nBWController *bwc_new(Messenger *m, uint32_t friendnumber,\n                      void (*mcb) (BWController *, uint32_t, float, void *),\n                      void *udata)\n{\n    BWController *retu = calloc(sizeof(struct BWController_s), 1);\n\n    retu->mcb = mcb;\n    retu->mcb_data = udata;\n    retu->m = m;\n    retu->friend_number = friendnumber;\n    retu->cycle.lsu = retu->cycle.lfu = current_time_monotonic();\n    retu->rcvpkt.rb = rb_new(BWC_AVG_PKT_COUNT);\n\n    /* Fill with zeros */\n    int i = 0;\n\n    for (; i < BWC_AVG_PKT_COUNT; i ++)\n        rb_write(retu->rcvpkt.rb, retu->rcvpkt.rb_s + i);\n\n    m_callback_rtp_packet(m, friendnumber, BWC_PACKET_ID, bwc_handle_data, retu);\n\n    return retu;\n}\nvoid bwc_kill(BWController *bwc)\n{\n    if (!bwc)\n        return;\n\n    m_callback_rtp_packet(bwc->m, bwc->friend_number, BWC_PACKET_ID, NULL, NULL);\n\n    rb_kill(bwc->rcvpkt.rb);\n    free(bwc);\n}\nvoid bwc_feed_avg(BWController *bwc, uint32_t bytes)\n{\n    uint32_t *p;\n\n    rb_read(bwc->rcvpkt.rb, (void **) &p);\n    rb_write(bwc->rcvpkt.rb, p);\n\n    *p = bytes;\n}\nvoid bwc_add_lost(BWController *bwc, uint32_t bytes)\n{\n    if (!bwc)\n        return;\n\n    if (!bytes) {\n        uint32_t *t_avg[BWC_AVG_PKT_COUNT], c = 1;\n\n        rb_data(bwc->rcvpkt.rb, (void **) t_avg);\n\n        int i = 0;\n\n        for (; i < BWC_AVG_PKT_COUNT; i ++) {\n            bytes += *(t_avg[i]);\n\n            if (*(t_avg[i]))\n                c++;\n        }\n\n        bytes /= c;\n    }\n\n    bwc->cycle.lost += bytes;\n    send_update(bwc);\n}\nvoid bwc_add_recv(BWController *bwc, uint32_t bytes)\n{\n    if (!bwc || !bytes)\n        return;\n\n    bwc->cycle.recv += bytes;\n    send_update(bwc);\n}\n\n\nstruct BWCMessage {\n    uint32_t lost;\n    uint32_t recv;\n};\n\nvoid send_update(BWController *bwc)\n{\n    if (current_time_monotonic() - bwc->cycle.lfu > BWC_REFRESH_INTERVAL_MS) {\n\n        bwc->cycle.lost /= 10;\n        bwc->cycle.recv /= 10;\n        bwc->cycle.lfu = current_time_monotonic();\n    } else if (current_time_monotonic() - bwc->cycle.lsu > BWC_SEND_INTERVAL_MS) {\n\n        if (bwc->cycle.lost) {\n            LOGGER_DEBUG (\"%p Sent update rcv: %u lost: %u\",\n                          bwc, bwc->cycle.recv, bwc->cycle.lost);\n\n            uint8_t p_msg[sizeof(struct BWCMessage) + 1];\n            struct BWCMessage *b_msg = (struct BWCMessage *)(p_msg + 1);\n\n            p_msg[0] = BWC_PACKET_ID;\n            b_msg->lost = htonl(bwc->cycle.lost);\n            b_msg->recv = htonl(bwc->cycle.recv);\n\n            if (-1 == send_custom_lossy_packet(bwc->m, bwc->friend_number, p_msg, sizeof(p_msg)))\n                LOGGER_WARNING(\"BWC send failed (len: %d)! std error: %s\", sizeof(p_msg), strerror(errno));\n        }\n\n        bwc->cycle.lsu = current_time_monotonic();\n    }\n}\nint on_update (BWController *bwc, struct BWCMessage *msg)\n{\n    LOGGER_DEBUG (\"%p Got update from peer\", bwc);\n\n    /* Peer must respect time boundary */\n    if (current_time_monotonic() < bwc->cycle.lru + BWC_SEND_INTERVAL_MS) {\n        LOGGER_DEBUG(\"%p Rejecting extra update\", bwc);\n        return -1;\n    }\n\n    bwc->cycle.lru = current_time_monotonic();\n\n    msg->recv = ntohl(msg->recv);\n    msg->lost = ntohl(msg->lost);\n\n    LOGGER_DEBUG (\"recved: %u lost: %u\", msg->recv, msg->lost);\n\n    if (msg->lost && bwc->mcb)\n        bwc->mcb(bwc, bwc->friend_number,\n                 ((float) (msg->lost) / (msg->recv + msg->lost)),\n                 bwc->mcb_data);\n\n    return 0;\n}\nint bwc_handle_data(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object)\n{\n    if (length - 1 != sizeof(struct BWCMessage))\n        return -1;\n\n    /* NOTE the data is mutable */\n    return on_update(object, (struct BWCMessage *) (data + 1));\n}\n"
  },
  {
    "path": "toxav/bwcontroller.h",
    "content": "/**  bwcontroller.h\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef BWCONROLER_H\n#define BWCONROLER_H\n#include \"../toxcore/Messenger.h\"\n\ntypedef struct BWController_s BWController;\n\nBWController *bwc_new(Messenger *m, uint32_t friendnumber,\n                      void (*mcb) (BWController *, uint32_t, float, void *),\n                      void *udata);\nvoid bwc_kill(BWController *bwc);\n\nvoid bwc_feed_avg(BWController *bwc, uint32_t bytes);\nvoid bwc_add_lost(BWController *bwc, uint32_t bytes);\nvoid bwc_add_recv(BWController *bwc, uint32_t bytes);\n\n#endif /* BWCONROLER_H */\n"
  },
  {
    "path": "toxav/group.c",
    "content": "/**  groupav.h\n *\n *   Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include \"group.h\"\n#include \"../toxcore/util.h\"\n#include \"../toxcore/logger.h\"\n\n#define GROUP_JBUF_SIZE 6\n#define GROUP_JBUF_DEAD_SECONDS 4\n\ntypedef struct {\n    uint16_t sequnum;\n    uint16_t length;\n    uint8_t data[];\n} Group_Audio_Packet;\n\ntypedef struct {\n    Group_Audio_Packet **queue;\n    uint32_t size;\n    uint32_t capacity;\n    uint16_t bottom;\n    uint16_t top;\n    uint64_t last_queued_time;\n} Group_JitterBuffer;\n\nstatic Group_JitterBuffer *create_queue(unsigned int capacity)\n{\n    unsigned int size = 1;\n\n    while (size <= capacity) {\n        size *= 2;\n    }\n\n    Group_JitterBuffer *q;\n\n    if (!(q = calloc(sizeof(Group_JitterBuffer), 1))) return NULL;\n\n    if (!(q->queue = calloc(sizeof(Group_Audio_Packet *), size))) {\n        free(q);\n        return NULL;\n    }\n\n    q->size = size;\n    q->capacity = capacity;\n    return q;\n}\n\nstatic void clear_queue(Group_JitterBuffer *q)\n{\n    for (; q->bottom != q->top; ++q->bottom) {\n        if (q->queue[q->bottom % q->size]) {\n            free(q->queue[q->bottom % q->size]);\n            q->queue[q->bottom % q->size] = NULL;\n        }\n    }\n}\n\nstatic void terminate_queue(Group_JitterBuffer *q)\n{\n    if (!q) return;\n\n    clear_queue(q);\n    free(q->queue);\n    free(q);\n}\n\n/* Return 0 if packet was queued, -1 if it wasn't.\n */\nstatic int queue(Group_JitterBuffer *q, Group_Audio_Packet *pk)\n{\n    uint16_t sequnum = pk->sequnum;\n\n    unsigned int num = sequnum % q->size;\n\n    if (!is_timeout(q->last_queued_time, GROUP_JBUF_DEAD_SECONDS)) {\n        if ((uint32_t)(sequnum - q->bottom) > (1 << 15)) {\n            /* Drop old packet. */\n            return -1;\n        }\n    }\n\n    if ((uint32_t)(sequnum - q->bottom) > q->size) {\n        clear_queue(q);\n        q->bottom = sequnum - q->capacity;\n        q->queue[num] = pk;\n        q->top = sequnum + 1;\n        q->last_queued_time = unix_time();\n        return 0;\n    }\n\n    if (q->queue[num])\n        return -1;\n\n    q->queue[num] = pk;\n\n    if ((sequnum - q->bottom) >= (q->top - q->bottom))\n        q->top = sequnum + 1;\n\n    q->last_queued_time = unix_time();\n    return 0;\n}\n\n/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */\nstatic Group_Audio_Packet *dequeue(Group_JitterBuffer *q, int *success)\n{\n    if (q->top == q->bottom) {\n        *success = 0;\n        return NULL;\n    }\n\n    unsigned int num = q->bottom % q->size;\n\n    if (q->queue[num]) {\n        Group_Audio_Packet *ret = q->queue[num];\n        q->queue[num] = NULL;\n        ++q->bottom;\n        *success = 1;\n        return ret;\n    }\n\n    if ((uint32_t)(q->top - q->bottom) > q->capacity) {\n        ++q->bottom;\n        *success = 2;\n        return NULL;\n    }\n\n    *success = 0;\n    return NULL;\n}\n\ntypedef struct {\n    Group_Chats *g_c;\n    OpusEncoder *audio_encoder;\n\n    unsigned int audio_channels, audio_sample_rate, audio_bitrate;\n\n    uint16_t audio_sequnum;\n\n    void (*audio_data)(Messenger *m, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples,\n                       uint8_t channels, unsigned int sample_rate, void *userdata);\n    void *userdata;\n} Group_AV;\n\ntypedef struct {\n    Group_JitterBuffer *buffer;\n\n    OpusDecoder *audio_decoder;\n    int decoder_channels;\n    unsigned int last_packet_samples;\n} Group_Peer_AV;\n\nstatic void kill_group_av(Group_AV *group_av)\n{\n    if (group_av->audio_encoder) {\n        opus_encoder_destroy(group_av->audio_encoder);\n    }\n\n    free(group_av);\n}\n\nstatic int recreate_encoder(Group_AV *group_av)\n{\n    if (group_av->audio_encoder) {\n        opus_encoder_destroy(group_av->audio_encoder);\n        group_av->audio_encoder = NULL;\n    }\n\n    int rc = OPUS_OK;\n    group_av->audio_encoder = opus_encoder_create(group_av->audio_sample_rate, group_av->audio_channels,\n                              OPUS_APPLICATION_AUDIO, &rc);\n\n    if (rc != OPUS_OK) {\n        LOGGER_ERROR(\"Error while starting audio encoder: %s\", opus_strerror(rc));\n        group_av->audio_encoder = NULL;\n        return -1;\n    }\n\n    rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_BITRATE(group_av->audio_bitrate));\n\n    if (rc != OPUS_OK) {\n        LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(rc));\n        opus_encoder_destroy(group_av->audio_encoder);\n        group_av->audio_encoder = NULL;\n        return -1;\n    }\n\n    rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_COMPLEXITY(10));\n\n    if (rc != OPUS_OK) {\n        LOGGER_ERROR(\"Error while setting encoder ctl: %s\", opus_strerror(rc));\n        opus_encoder_destroy(group_av->audio_encoder);\n        group_av->audio_encoder = NULL;\n        return -1;\n    }\n\n    return 0;\n}\n\nstatic Group_AV *new_group_av(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *,\n                              unsigned int, uint8_t, unsigned int, void *), void *userdata)\n{\n    if (!g_c)\n        return NULL;\n\n    Group_AV *group_av = calloc(1, sizeof(Group_AV));\n\n    if (!group_av)\n        return NULL;\n\n    group_av->g_c = g_c;\n\n    group_av->audio_data = audio_callback;\n    group_av->userdata = userdata;\n\n    return group_av;\n}\n\nstatic void group_av_peer_new(void *object, int groupnumber, int friendgroupnumber)\n{\n    Group_AV *group_av = object;\n    Group_Peer_AV *peer_av = calloc(1, sizeof(Group_Peer_AV));\n\n    if (!peer_av)\n        return;\n\n    peer_av->buffer = create_queue(GROUP_JBUF_SIZE);\n    group_peer_set_object(group_av->g_c, groupnumber, friendgroupnumber, peer_av);\n}\n\nstatic void group_av_peer_delete(void *object, int groupnumber, int friendgroupnumber, void *peer_object)\n{\n    Group_Peer_AV *peer_av = peer_object;\n\n    if (!peer_av)\n        return;\n\n    if (peer_av->audio_decoder)\n        opus_decoder_destroy(peer_av->audio_decoder);\n\n    terminate_queue(peer_av->buffer);\n    free(peer_object);\n}\n\nstatic void group_av_groupchat_delete(void *object, int groupnumber)\n{\n    if (object)\n        kill_group_av(object);\n}\n\nstatic int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int groupnumber, int friendgroupnumber)\n{\n    if (!group_av || !peer_av)\n        return -1;\n\n    int success;\n    Group_Audio_Packet *pk = dequeue(peer_av->buffer, &success);\n\n    if (success == 0)\n        return -1;\n\n    int16_t *out_audio = NULL;\n    int out_audio_samples = 0;\n\n    unsigned int sample_rate = 48000;\n\n    if (success == 1) {\n        int channels = opus_packet_get_nb_channels(pk->data);\n\n        if (channels == OPUS_INVALID_PACKET) {\n            free(pk);\n            return -1;\n        }\n\n        if (channels != 1 && channels != 2) {\n            free(pk);\n            return -1;\n        }\n\n        if (channels != peer_av->decoder_channels) {\n            if (peer_av->audio_decoder) {\n                opus_decoder_destroy(peer_av->audio_decoder);\n                peer_av->audio_decoder = NULL;\n            }\n\n            int rc;\n            peer_av->audio_decoder = opus_decoder_create(sample_rate, channels, &rc);\n\n            if (rc != OPUS_OK) {\n                LOGGER_ERROR(\"Error while starting audio decoder: %s\", opus_strerror(rc));\n                free(pk);\n                return -1;\n            }\n\n            peer_av->decoder_channels = channels;\n        }\n\n        int num_samples = opus_decoder_get_nb_samples(peer_av->audio_decoder, pk->data, pk->length);\n\n        out_audio = malloc(num_samples * peer_av->decoder_channels * sizeof(int16_t));\n\n        if (!out_audio) {\n            free(pk);\n            return -1;\n        }\n\n        out_audio_samples = opus_decode(peer_av->audio_decoder, pk->data, pk->length, out_audio, num_samples, 0);\n        free(pk);\n\n        if (out_audio_samples <= 0)\n            return -1;\n\n        peer_av->last_packet_samples = out_audio_samples;\n    } else {\n        if (!peer_av->audio_decoder)\n            return -1;\n\n        if (!peer_av->last_packet_samples)\n            return -1;\n\n        out_audio = malloc(peer_av->last_packet_samples * peer_av->decoder_channels * sizeof(int16_t));\n\n        if (!out_audio) {\n            free(pk);\n            return -1;\n        }\n\n        out_audio_samples = opus_decode(peer_av->audio_decoder, NULL, 0, out_audio, peer_av->last_packet_samples, 1);\n\n        if (out_audio_samples <= 0)\n            return -1;\n\n    }\n\n    if (out_audio) {\n\n        if (group_av->audio_data)\n            group_av->audio_data(group_av->g_c->m, groupnumber, friendgroupnumber, out_audio, out_audio_samples,\n                                 peer_av->decoder_channels, sample_rate, group_av->userdata);\n\n        free(out_audio);\n        return 0;\n    }\n\n    return -1;\n}\n\nstatic int handle_group_audio_packet(void *object, int groupnumber, int friendgroupnumber, void *peer_object,\n                                     const uint8_t *packet, uint16_t length)\n{\n    if (!peer_object || !object || length <= sizeof(uint16_t)) {\n        return -1;\n    }\n\n    Group_Peer_AV *peer_av = peer_object;\n\n    Group_Audio_Packet *pk = calloc(1, sizeof(Group_Audio_Packet) + (length - sizeof(uint16_t)));\n\n    if (!pk) {\n        return -1;\n    }\n\n    uint16_t sequnum;\n    memcpy(&sequnum, packet, sizeof(sequnum));\n    pk->sequnum = ntohs(sequnum);\n    pk->length = length - sizeof(uint16_t);\n    memcpy(pk->data, packet + sizeof(uint16_t), length - sizeof(uint16_t));\n\n    if (queue(peer_av->buffer, pk) == -1) {\n        free(pk);\n        return -1;\n    }\n\n    while (decode_audio_packet(object, peer_av, groupnumber, friendgroupnumber) == 0);\n\n    return 0;\n}\n\n/* Convert groupchat to an A/V groupchat.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nstatic int groupchat_enable_av(Group_Chats *g_c, int groupnumber, void (*audio_callback)(Messenger *, int, int,\n                               const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)\n{\n    if (groupnumber == -1)\n        return -1;\n\n    Group_AV *group_av = new_group_av(g_c, audio_callback, userdata);\n\n    if (group_av == NULL)\n        return -1;\n\n    if (group_set_object(g_c, groupnumber, group_av) == -1\n            || callback_groupchat_peer_new(g_c, groupnumber, group_av_peer_new) == -1\n            || callback_groupchat_peer_delete(g_c, groupnumber, group_av_peer_delete) == -1\n            || callback_groupchat_delete(g_c, groupnumber, group_av_groupchat_delete) == -1) {\n        kill_group_av(group_av);\n        return -1;\n    }\n\n    group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet);\n    return 0;\n}\n\n/* Create a new toxav group.\n *\n * return group number on success.\n * return -1 on failure.\n */\nint add_av_groupchat(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int,\n                     uint8_t, unsigned int, void *), void *userdata)\n{\n    int groupnumber = add_groupchat(g_c, GROUPCHAT_TYPE_AV);\n\n    if (groupnumber == -1) {\n        return -1;\n    }\n\n    if (groupchat_enable_av(g_c, groupnumber, audio_callback, userdata) == -1) {\n        del_groupchat(g_c, groupnumber);\n        return -1;\n    }\n\n    return groupnumber;\n}\n\n/* Join a AV group (you need to have been invited first.)\n *\n * returns group number on success\n * returns -1 on failure.\n */\nint join_av_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length,\n                      void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),\n                      void *userdata)\n{\n    int groupnumber = join_groupchat(g_c, friendnumber, GROUPCHAT_TYPE_AV, data, length);\n\n    if (groupnumber == -1) {\n        return -1;\n    }\n\n    if (groupchat_enable_av(g_c, groupnumber, audio_callback, userdata) == -1) {\n        del_groupchat(g_c, groupnumber);\n        return -1;\n    }\n\n    return groupnumber;\n}\n\n/* Send an encoded audio packet to the group chat.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nstatic int send_audio_packet(Group_Chats *g_c, int groupnumber, uint8_t *packet, uint16_t length)\n{\n    if (!length)\n        return -1;\n\n    Group_AV *group_av = group_get_object(g_c, groupnumber);\n    uint8_t data[1 + sizeof(uint16_t) + length];\n    data[0] = GROUP_AUDIO_PACKET_ID;\n\n    uint16_t sequnum = htons(group_av->audio_sequnum);\n    memcpy(data + 1, &sequnum, sizeof(sequnum));\n    memcpy(data + 1 + sizeof(sequnum), packet, length);\n\n    if (send_group_lossy_packet(g_c, groupnumber, data, sizeof(data)) == -1)\n        return -1;\n\n    ++group_av->audio_sequnum;\n    return 0;\n}\n\n/* Send audio to the group chat.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,\n                     unsigned int sample_rate)\n{\n    Group_AV *group_av = group_get_object(g_c, groupnumber);\n\n    if (!group_av)\n        return -1;\n\n    if (channels != 1 && channels != 2)\n        return -1;\n\n    if (sample_rate != 8000 && sample_rate != 12000 && sample_rate != 16000 && sample_rate != 24000 && sample_rate != 48000)\n        return -1;\n\n    if (!group_av->audio_encoder || group_av->audio_channels != channels || group_av->audio_sample_rate != sample_rate) {\n        group_av->audio_channels = channels;\n        group_av->audio_sample_rate = sample_rate;\n\n        if (channels == 1) {\n            group_av->audio_bitrate = 32000; //TODO: add way of adjusting bitrate\n        } else {\n            group_av->audio_bitrate = 64000; //TODO: add way of adjusting bitrate\n        }\n\n        if (recreate_encoder(group_av) == -1)\n            return -1;\n    }\n\n    uint8_t encoded[1024];\n    int32_t size = opus_encode(group_av->audio_encoder, pcm, samples, encoded, sizeof(encoded));\n\n    if (size <= 0)\n        return -1;\n\n    return send_audio_packet(g_c, groupnumber, encoded, size);\n}\n"
  },
  {
    "path": "toxav/group.h",
    "content": "/**  groupav.c\n *\n *   Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n */\n\n/* Audio encoding/decoding */\n#include <opus.h>\n\n#include \"../toxcore/group.h\"\n\n#define GROUP_AUDIO_PACKET_ID 192\n\n/* Create a new toxav group.\n *\n * return group number on success.\n * return -1 on failure.\n */\nint add_av_groupchat(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int,\n                     uint8_t, unsigned int, void *), void *userdata);\n\n/* Join a AV group (you need to have been invited first.)\n *\n * returns group number on success\n * returns -1 on failure.\n */\nint join_av_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length,\n                      void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),\n                      void *userdata);\n\n\n/* Send audio to the group chat.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,\n                     unsigned int sample_rate);\n\n"
  },
  {
    "path": "toxav/msi.c",
    "content": "/**  msi.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include \"msi.h\"\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/util.h\"\n\n#include <unistd.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdbool.h>\n#include <assert.h>\n\n#define MSI_MAXMSG_SIZE 256\n\n/**\n * Protocol:\n *\n * |id [1 byte]| |size [1 byte]| |data [$size bytes]| |...{repeat}| |0 {end byte}|\n */\n\ntypedef enum {\n    IDRequest = 1,\n    IDError,\n    IDCapabilities,\n\n} MSIHeaderID;\n\n\ntypedef enum {\n    requ_init,\n    requ_push,\n    requ_pop,\n} MSIRequest;\n\n\n#define GENERIC_HEADER(header, val_type) \\\ntypedef struct { \\\n    val_type value; \\\n    bool exists; \\\n} MSIHeader##header\n\n\nGENERIC_HEADER (Request, MSIRequest);\nGENERIC_HEADER (Error, MSIError);\nGENERIC_HEADER (Capabilities, uint8_t);\n\n\ntypedef struct {\n    MSIHeaderRequest      request;\n    MSIHeaderError        error;\n    MSIHeaderCapabilities capabilities;\n} MSIMessage;\n\n\nvoid msg_init (MSIMessage *dest, MSIRequest request);\nint msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length);\nuint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length);\nstatic int send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg);\nint send_error (Messenger *m, uint32_t friend_number, MSIError error);\nstatic int invoke_callback(MSICall *call, MSICallbackID cb);\nstatic MSICall *get_call (MSISession *session, uint32_t friend_number);\nMSICall *new_call (MSISession *session, uint32_t friend_number);\nvoid kill_call (MSICall *call);\nvoid on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data);\nvoid handle_init (MSICall *call, const MSIMessage *msg);\nvoid handle_push (MSICall *call, const MSIMessage *msg);\nvoid handle_pop (MSICall *call, const MSIMessage *msg);\nvoid handle_msi_packet (Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object);\n\n\n/**\n * Public functions\n */\nvoid msi_register_callback (MSISession *session, msi_action_cb *callback, MSICallbackID id)\n{\n    if (!session)\n        return;\n\n    pthread_mutex_lock(session->mutex);\n    session->callbacks[id] = callback;\n    pthread_mutex_unlock(session->mutex);\n}\nMSISession *msi_new (Messenger *m)\n{\n    if (m == NULL) {\n        LOGGER_ERROR(\"Could not init session on empty messenger!\");\n        return NULL;\n    }\n\n    MSISession *retu = calloc (sizeof (MSISession), 1);\n\n    if (retu == NULL) {\n        LOGGER_ERROR(\"Allocation failed! Program might misbehave!\");\n        return NULL;\n    }\n\n    if (create_recursive_mutex(retu->mutex) != 0) {\n        LOGGER_ERROR(\"Failed to init mutex! Program might misbehave\");\n        free(retu);\n        return NULL;\n    }\n\n    retu->messenger = m;\n\n    m_callback_msi_packet(m, handle_msi_packet, retu);\n\n    /* This is called when remote terminates session */\n    m_callback_connectionstatus_internal_av(m, on_peer_status, retu);\n\n    LOGGER_DEBUG(\"New msi session: %p \", retu);\n    return retu;\n}\nint msi_kill (MSISession *session)\n{\n    if (session == NULL) {\n        LOGGER_ERROR(\"Tried to terminate non-existing session\");\n        return -1;\n    }\n\n    m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL);\n\n    if (pthread_mutex_trylock(session->mutex) != 0) {\n        LOGGER_ERROR (\"Failed to aquire lock on msi mutex\");\n        return -1;\n    }\n\n    if (session->calls) {\n        MSIMessage msg;\n        msg_init(&msg, requ_pop);\n\n        MSICall *it = get_call(session, session->calls_head);\n\n        while (it) {\n            send_message(session->messenger, it->friend_number, &msg);\n            MSICall *temp_it = it;\n            it = it->next;\n            kill_call(temp_it); /* This will eventually free session->calls */\n        }\n    }\n\n    pthread_mutex_unlock(session->mutex);\n    pthread_mutex_destroy(session->mutex);\n\n    LOGGER_DEBUG(\"Terminated session: %p\", session);\n    free (session);\n    return 0;\n}\nint msi_invite (MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities)\n{\n    if (!session)\n        return -1;\n\n    LOGGER_DEBUG(\"Session: %p Inviting friend: %u\", session, friend_number);\n\n    if (pthread_mutex_trylock(session->mutex) != 0) {\n        LOGGER_ERROR (\"Failed to aquire lock on msi mutex\");\n        return -1;\n    }\n\n    if (get_call(session, friend_number) != NULL) {\n        LOGGER_ERROR(\"Already in a call\");\n        pthread_mutex_unlock(session->mutex);\n        return -1;\n    }\n\n    (*call) = new_call (session, friend_number);\n\n    if (*call == NULL) {\n        pthread_mutex_unlock(session->mutex);\n        return -1;\n    }\n\n    (*call)->self_capabilities = capabilities;\n\n    MSIMessage msg;\n    msg_init(&msg, requ_init);\n\n    msg.capabilities.exists = true;\n    msg.capabilities.value = capabilities;\n\n    send_message ((*call)->session->messenger, (*call)->friend_number, &msg);\n\n    (*call)->state = msi_CallRequesting;\n\n    LOGGER_DEBUG(\"Invite sent\");\n    pthread_mutex_unlock(session->mutex);\n    return 0;\n}\nint msi_hangup (MSICall *call)\n{\n    if (!call || !call->session)\n        return -1;\n\n    LOGGER_DEBUG(\"Session: %p Hanging up call with friend: %u\", call->session, call->friend_number);\n\n    MSISession *session = call->session;\n\n    if (pthread_mutex_trylock(session->mutex) != 0) {\n        LOGGER_ERROR (\"Failed to aquire lock on msi mutex\");\n        return -1;\n    }\n\n    if (call->state == msi_CallInactive) {\n        LOGGER_ERROR(\"Call is in invalid state!\");\n        pthread_mutex_unlock(session->mutex);\n        return -1;\n    }\n\n    MSIMessage msg;\n    msg_init(&msg, requ_pop);\n\n    send_message (session->messenger, call->friend_number, &msg);\n\n    kill_call(call);\n    pthread_mutex_unlock(session->mutex);\n    return 0;\n}\nint msi_answer (MSICall *call, uint8_t capabilities)\n{\n    if (!call || !call->session)\n        return -1;\n\n    LOGGER_DEBUG(\"Session: %p Answering call from: %u\", call->session, call->friend_number);\n\n    MSISession *session = call->session;\n\n    if (pthread_mutex_trylock(session->mutex) != 0) {\n        LOGGER_ERROR (\"Failed to aquire lock on msi mutex\");\n        return -1;\n    }\n\n    if (call->state != msi_CallRequested) {\n        /* Though sending in invalid state will not cause anything wierd\n         * Its better to not do it like a maniac */\n        LOGGER_ERROR(\"Call is in invalid state!\");\n        pthread_mutex_unlock(session->mutex);\n        return -1;\n    }\n\n    call->self_capabilities = capabilities;\n\n    MSIMessage msg;\n    msg_init(&msg, requ_push);\n\n    msg.capabilities.exists = true;\n    msg.capabilities.value = capabilities;\n\n    send_message (session->messenger, call->friend_number, &msg);\n\n    call->state = msi_CallActive;\n    pthread_mutex_unlock(session->mutex);\n\n    return 0;\n}\nint msi_change_capabilities(MSICall *call, uint8_t capabilities)\n{\n    if (!call || !call->session)\n        return -1;\n\n    LOGGER_DEBUG(\"Session: %p Trying to change capabilities to friend %u\", call->session, call->friend_number);\n\n    MSISession *session = call->session;\n\n    if (pthread_mutex_trylock(session->mutex) != 0) {\n        LOGGER_ERROR (\"Failed to aquire lock on msi mutex\");\n        return -1;\n    }\n\n    if (call->state != msi_CallActive) {\n        LOGGER_ERROR(\"Call is in invalid state!\");\n        pthread_mutex_unlock(session->mutex);\n        return -1;\n    }\n\n    call->self_capabilities = capabilities;\n\n    MSIMessage msg;\n    msg_init(&msg, requ_push);\n\n    msg.capabilities.exists = true;\n    msg.capabilities.value = capabilities;\n\n    send_message (call->session->messenger, call->friend_number, &msg);\n\n    pthread_mutex_unlock(session->mutex);\n    return 0;\n}\n\n\n/**\n * Private functions\n */\nvoid msg_init(MSIMessage *dest, MSIRequest request)\n{\n    memset(dest, 0, sizeof(*dest));\n    dest->request.exists = true;\n    dest->request.value = request;\n}\nint msg_parse_in (MSIMessage *dest, const uint8_t *data, uint16_t length)\n{\n    /* Parse raw data received from socket into MSIMessage struct */\n\n#define CHECK_SIZE(bytes, constraint, size) \\\n    if ((constraint -= (2 + size)) < 1) { LOGGER_ERROR(\"Read over length!\"); return -1; } \\\n    if (bytes[1] != size) { LOGGER_ERROR(\"Invalid data size!\"); return -1; }\n\n#define CHECK_ENUM_HIGH(bytes, enum_high) /* Assumes size == 1 */ \\\n    if (bytes[2] > enum_high) { LOGGER_ERROR(\"Failed enum high limit!\"); return -1; }\n\n#define SET_UINT8(bytes, header) do { \\\n        header.value = bytes[2]; \\\n        header.exists = true; \\\n        bytes += 3; \\\n    } while(0)\n\n#define SET_UINT16(bytes, header) do { \\\n        memcpy(&header.value, bytes + 2, 2);\\\n        header.exists = true; \\\n        bytes += 4; \\\n    } while(0)\n\n\n    assert(dest);\n\n    if (length == 0 || data[length - 1]) { /* End byte must have value 0 */\n        LOGGER_ERROR(\"Invalid end byte\");\n        return -1;\n    }\n\n    memset(dest, 0, sizeof(*dest));\n\n    const uint8_t *it = data;\n    int size_constraint = length;\n\n    while (*it) {/* until end byte is hit */\n        switch (*it) {\n            case IDRequest:\n                CHECK_SIZE(it, size_constraint, 1);\n                CHECK_ENUM_HIGH(it, requ_pop);\n                SET_UINT8(it, dest->request);\n                break;\n\n            case IDError:\n                CHECK_SIZE(it, size_constraint, 1);\n                CHECK_ENUM_HIGH(it, msi_EUndisclosed);\n                SET_UINT8(it, dest->error);\n                break;\n\n            case IDCapabilities:\n                CHECK_SIZE(it, size_constraint, 1);\n                SET_UINT8(it, dest->capabilities);\n                break;\n\n            default:\n                LOGGER_ERROR(\"Invalid id byte\");\n                return -1;\n                break;\n        }\n    }\n\n    if (dest->request.exists == false) {\n        LOGGER_ERROR(\"Invalid request field!\");\n        return -1;\n    }\n\n    return 0;\n\n#undef CHECK_SIZE\n#undef CHECK_ENUM_HIGH\n#undef SET_UINT8\n#undef SET_UINT16\n}\nuint8_t *msg_parse_header_out (MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length)\n{\n    /* Parse a single header for sending */\n    assert(dest);\n    assert(value);\n    assert(value_len);\n\n    *dest = id;\n    dest ++;\n    *dest = value_len;\n    dest ++;\n\n    memcpy(dest, value, value_len);\n\n    *length += (2 + value_len);\n\n    return dest + value_len; /* Set to next position ready to be written */\n}\nint send_message (Messenger *m, uint32_t friend_number, const MSIMessage *msg)\n{\n    /* Parse and send message */\n    assert(m);\n\n    uint8_t parsed [MSI_MAXMSG_SIZE];\n\n    uint8_t *it = parsed;\n    uint16_t size = 0;\n\n    if (msg->request.exists) {\n        uint8_t cast = msg->request.value;\n        it = msg_parse_header_out(IDRequest, it, &cast,\n                                  sizeof(cast), &size);\n    } else {\n        LOGGER_DEBUG(\"Must have request field\");\n        return -1;\n    }\n\n    if (msg->error.exists) {\n        uint8_t cast = msg->error.value;\n        it = msg_parse_header_out(IDError, it, &cast,\n                                  sizeof(cast), &size);\n    }\n\n    if (msg->capabilities.exists) {\n        it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value,\n                                  sizeof(msg->capabilities.value), &size);\n    }\n\n    if (it == parsed) {\n        LOGGER_WARNING(\"Parsing message failed; empty message\");\n        return -1;\n    }\n\n    *it = 0;\n    size ++;\n\n    if (m_msi_packet(m, friend_number, parsed, size)) {\n        LOGGER_DEBUG(\"Sent message\");\n        return 0;\n    }\n\n    return -1;\n}\nint send_error (Messenger *m, uint32_t friend_number, MSIError error)\n{\n    /* Send error message */\n    assert(m);\n\n    LOGGER_DEBUG(\"Sending error: %d to friend: %d\", error, friend_number);\n\n    MSIMessage msg;\n    msg_init(&msg, requ_pop);\n\n    msg.error.exists = true;\n    msg.error.value = error;\n\n    send_message (m, friend_number, &msg);\n    return 0;\n}\nint invoke_callback(MSICall *call, MSICallbackID cb)\n{\n    assert(call);\n\n    if (call->session->callbacks[cb]) {\n        LOGGER_DEBUG(\"Invoking callback function: %d\", cb);\n\n        if (call->session->callbacks[cb] (call->session->av, call) != 0) {\n            LOGGER_WARNING(\"Callback state handling failed, sending error\");\n            goto FAILURE;\n        }\n\n        return 0;\n    }\n\nFAILURE:\n    /* If no callback present or error happened while handling,\n     * an error message will be sent to friend\n     */\n\n    if (call->error == msi_ENone)\n        call->error = msi_EHandle;\n\n    return -1;\n}\nstatic MSICall *get_call (MSISession *session, uint32_t friend_number)\n{\n    assert(session);\n\n    if (session->calls == NULL || session->calls_tail < friend_number)\n        return NULL;\n\n    return session->calls[friend_number];\n}\nMSICall *new_call (MSISession *session, uint32_t friend_number)\n{\n    assert(session);\n\n    MSICall *rc = calloc(sizeof(MSICall), 1);\n\n    if (rc == NULL)\n        return NULL;\n\n    rc->session = session;\n    rc->friend_number = friend_number;\n\n    if (session->calls == NULL) { /* Creating */\n        session->calls = calloc (sizeof(MSICall *), friend_number + 1);\n\n        if (session->calls == NULL) {\n            free(rc);\n            return NULL;\n        }\n\n        session->calls_tail = session->calls_head = friend_number;\n\n    } else if (session->calls_tail < friend_number) { /* Appending */\n        void *tmp = realloc(session->calls, sizeof(MSICall *) * (friend_number + 1));\n\n        if (tmp == NULL) {\n            free(rc);\n            return NULL;\n        }\n\n        session->calls = tmp;\n\n        /* Set fields in between to null */\n        uint32_t i = session->calls_tail + 1;\n\n        for (; i < friend_number; i ++)\n            session->calls[i] = NULL;\n\n        rc->prev = session->calls[session->calls_tail];\n        session->calls[session->calls_tail]->next = rc;\n\n        session->calls_tail = friend_number;\n\n    } else if (session->calls_head > friend_number) { /* Inserting at front */\n        rc->next = session->calls[session->calls_head];\n        session->calls[session->calls_head]->prev = rc;\n        session->calls_head = friend_number;\n    }\n\n    session->calls[friend_number] = rc;\n    return rc;\n}\nvoid kill_call (MSICall *call)\n{\n    /* Assume that session mutex is locked */\n    if (call == NULL)\n        return;\n\n    LOGGER_DEBUG(\"Killing call: %p\", call);\n\n    MSISession *session = call->session;\n\n    MSICall *prev = call->prev;\n    MSICall *next = call->next;\n\n    if (prev)\n        prev->next = next;\n    else if (next)\n        session->calls_head = next->friend_number;\n    else goto CLEAR_CONTAINER;\n\n    if (next)\n        next->prev = prev;\n    else if (prev)\n        session->calls_tail = prev->friend_number;\n    else goto CLEAR_CONTAINER;\n\n    session->calls[call->friend_number] = NULL;\n    free(call);\n    return;\n\nCLEAR_CONTAINER:\n    session->calls_head = session->calls_tail = 0;\n    free(session->calls);\n    free(call);\n    session->calls = NULL;\n}\nvoid on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data)\n{\n    (void)m;\n    MSISession *session = data;\n\n    switch (status) {\n        case 0: { /* Friend is now offline */\n            LOGGER_DEBUG(\"Friend %d is now offline\", friend_number);\n\n            pthread_mutex_lock(session->mutex);\n            MSICall *call = get_call(session, friend_number);\n\n            if (call == NULL) {\n                pthread_mutex_unlock(session->mutex);\n                return;\n            }\n\n            invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */\n            kill_call(call);\n            pthread_mutex_unlock(session->mutex);\n        }\n        break;\n\n        default:\n            break;\n    }\n}\nvoid handle_init (MSICall *call, const MSIMessage *msg)\n{\n    assert(call);\n    LOGGER_DEBUG(\"Session: %p Handling 'init' friend: %d\", call->session, call->friend_number);\n\n    if (!msg->capabilities.exists) {\n        LOGGER_WARNING(\"Session: %p Invalid capabilities on 'init'\");\n        call->error = msi_EInvalidMessage;\n        goto FAILURE;\n    }\n\n    switch (call->state) {\n        case msi_CallInactive: {\n            /* Call requested */\n            call->peer_capabilities = msg->capabilities.value;\n            call->state = msi_CallRequested;\n\n            if (invoke_callback(call, msi_OnInvite) == -1)\n                goto FAILURE;\n        }\n        break;\n\n        case msi_CallActive: {\n            /* If peer sent init while the call is already\n             * active it's probable that he is trying to\n             * re-call us while the call is not terminated\n             * on our side. We can assume that in this case\n             * we can automatically answer the re-call.\n             */\n\n            LOGGER_INFO(\"Friend is recalling us\");\n\n            MSIMessage msg;\n            msg_init(&msg, requ_push);\n\n            msg.capabilities.exists = true;\n            msg.capabilities.value = call->self_capabilities;\n\n            send_message (call->session->messenger, call->friend_number, &msg);\n\n            /* If peer changed capabilities during re-call they will\n             * be handled accordingly during the next step\n             */\n        }\n        break;\n\n        default: {\n            LOGGER_WARNING(\"Session: %p Invalid state on 'init'\");\n            call->error = msi_EInvalidState;\n            goto FAILURE;\n        }\n        break;\n    }\n\n    return;\nFAILURE:\n    send_error(call->session->messenger, call->friend_number, call->error);\n    kill_call(call);\n}\nvoid handle_push (MSICall *call, const MSIMessage *msg)\n{\n    assert(call);\n\n    LOGGER_DEBUG(\"Session: %p Handling 'push' friend: %d\", call->session, call->friend_number);\n\n    if (!msg->capabilities.exists) {\n        LOGGER_WARNING(\"Session: %p Invalid capabilities on 'push'\");\n        call->error = msi_EInvalidMessage;\n        goto FAILURE;\n    }\n\n    switch (call->state) {\n        case msi_CallActive: {\n            /* Only act if capabilities changed */\n            if (call->peer_capabilities != msg->capabilities.value) {\n                LOGGER_INFO(\"Friend is changing capabilities to: %u\", msg->capabilities.value);\n\n                call->peer_capabilities = msg->capabilities.value;\n\n                if (invoke_callback(call, msi_OnCapabilities) == -1)\n                    goto FAILURE;\n            }\n        }\n        break;\n\n        case msi_CallRequesting: {\n            LOGGER_INFO(\"Friend answered our call\");\n\n            /* Call started */\n            call->peer_capabilities = msg->capabilities.value;\n            call->state = msi_CallActive;\n\n            if (invoke_callback(call, msi_OnStart) == -1)\n                goto FAILURE;\n\n        }\n        break;\n\n        /* Pushes during initialization state are ignored */\n        case msi_CallInactive:\n        case msi_CallRequested: {\n            LOGGER_WARNING(\"Ignoring invalid push\");\n        }\n        break;\n    }\n\n    return;\n\nFAILURE:\n    send_error(call->session->messenger, call->friend_number, call->error);\n    kill_call(call);\n}\nvoid handle_pop (MSICall *call, const MSIMessage *msg)\n{\n    assert(call);\n\n    LOGGER_DEBUG(\"Session: %p Handling 'pop', friend id: %d\", call->session, call->friend_number);\n\n    /* callback errors are ignored */\n\n    if (msg->error.exists) {\n        LOGGER_WARNING(\"Friend detected an error: %d\", msg->error.value);\n        call->error = msg->error.value;\n        invoke_callback(call, msi_OnError);\n\n    } else switch (call->state) {\n            case msi_CallInactive: {\n                LOGGER_ERROR(\"Handling what should be impossible case\");\n                abort();\n            }\n            break;\n\n            case msi_CallActive: {\n                /* Hangup */\n                LOGGER_INFO(\"Friend hung up on us\");\n                invoke_callback(call, msi_OnEnd);\n            }\n            break;\n\n            case msi_CallRequesting: {\n                /* Reject */\n                LOGGER_INFO(\"Friend rejected our call\");\n                invoke_callback(call, msi_OnEnd);\n            }\n            break;\n\n            case msi_CallRequested: {\n                /* Cancel */\n                LOGGER_INFO(\"Friend canceled call invite\");\n                invoke_callback(call, msi_OnEnd);\n            }\n            break;\n        }\n\n    kill_call (call);\n}\nvoid handle_msi_packet (Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object)\n{\n    LOGGER_DEBUG(\"Got msi message\");\n\n    MSISession *session = object;\n    MSIMessage msg;\n\n    if (msg_parse_in (&msg, data, length) == -1) {\n        LOGGER_WARNING(\"Error parsing message\");\n        send_error(m, friend_number, msi_EInvalidMessage);\n        return;\n    } else {\n        LOGGER_DEBUG(\"Successfully parsed message\");\n    }\n\n    pthread_mutex_lock(session->mutex);\n    MSICall *call = get_call(session, friend_number);\n\n    if (call == NULL) {\n        if (msg.request.value != requ_init) {\n            send_error(m, friend_number, msi_EStrayMessage);\n            pthread_mutex_unlock(session->mutex);\n            return;\n        }\n\n        call = new_call(session, friend_number);\n\n        if (call == NULL) {\n            send_error(m, friend_number, msi_ESystem);\n            pthread_mutex_unlock(session->mutex);\n            return;\n        }\n    }\n\n    switch (msg.request.value) {\n        case requ_init:\n            handle_init(call, &msg);\n            break;\n\n        case requ_push:\n            handle_push(call, &msg);\n            break;\n\n        case requ_pop:\n            handle_pop(call, &msg); /* always kills the call */\n            break;\n    }\n\n    pthread_mutex_unlock(session->mutex);\n}\n"
  },
  {
    "path": "toxav/msi.h",
    "content": "/**  msi.h\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef MSI_H\n#define MSI_H\n\n#include <inttypes.h>\n#include <pthread.h>\n\n#include \"audio.h\"\n#include \"video.h\"\n#include \"../toxcore/Messenger.h\"\n\n/**\n * Error codes.\n */\ntypedef enum {\n    msi_ENone,\n    msi_EInvalidMessage,\n    msi_EInvalidParam,\n    msi_EInvalidState,\n    msi_EStrayMessage,\n    msi_ESystem,\n    msi_EHandle,\n    msi_EUndisclosed, /* NOTE: must be last enum otherwise parsing will not work */\n} MSIError;\n\n/**\n * Supported capabilities\n */\ntypedef enum {\n    msi_CapSAudio = 4,  /* sending audio */\n    msi_CapSVideo = 8,  /* sending video */\n    msi_CapRAudio = 16, /* receiving audio */\n    msi_CapRVideo = 32, /* receiving video */\n} MSICapabilities;\n\n\n/**\n * Call state identifiers.\n */\ntypedef enum {\n    msi_CallInactive, /* Default */\n    msi_CallActive,\n    msi_CallRequesting, /* when sending call invite */\n    msi_CallRequested, /* when getting call invite */\n} MSICallState;\n\n/**\n * Callbacks ids that handle the states\n */\ntypedef enum {\n    msi_OnInvite, /* Incoming call */\n    msi_OnStart, /* Call (RTP transmission) started */\n    msi_OnEnd, /* Call that was active ended */\n    msi_OnError, /* On protocol error */\n    msi_OnPeerTimeout, /* Peer timed out; stop the call */\n    msi_OnCapabilities, /* Peer requested capabilities change */\n} MSICallbackID;\n\n/**\n * The call struct. Please do not modify outside msi.c\n */\ntypedef struct MSICall_s {\n    struct MSISession_s *session;           /* Session pointer */\n\n    MSICallState         state;\n    uint8_t              peer_capabilities; /* Peer capabilities */\n    uint8_t              self_capabilities; /* Self capabilities */\n    uint16_t             peer_vfpsz;        /* Video frame piece size */\n    uint32_t             friend_number;     /* Index of this call in MSISession */\n    MSIError             error;             /* Last error */\n\n    void                *av_call;           /* Pointer to av call handler */\n\n    struct MSICall_s    *next;\n    struct MSICall_s    *prev;\n} MSICall;\n\n\n/**\n * Expected return on success is 0, if any other number is\n * returned the call is considered errored and will be handled\n * as such which means it will be terminated without any notice.\n */\ntypedef int msi_action_cb (void *av, MSICall *call);\n\n/**\n * Control session struct. Please do not modify outside msi.c\n */\ntypedef struct MSISession_s {\n    /* Call handlers */\n    MSICall       **calls;\n    uint32_t        calls_tail;\n    uint32_t        calls_head;\n\n    void           *av;\n    Messenger      *messenger;\n\n    pthread_mutex_t mutex[1];\n    msi_action_cb *callbacks[7];\n} MSISession;\n\n/**\n * Start the control session.\n */\nMSISession *msi_new(Messenger *m);\n/**\n * Terminate control session. NOTE: all calls will be freed\n */\nint msi_kill(MSISession *session);\n/**\n * Callback setter.\n */\nvoid msi_register_callback(MSISession *session, msi_action_cb *callback, MSICallbackID id);\n/**\n * Send invite request to friend_number.\n */\nint msi_invite(MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities);\n/**\n * Hangup call. NOTE: 'call' will be freed\n */\nint msi_hangup(MSICall *call);\n/**\n * Answer call request.\n */\nint msi_answer(MSICall *call, uint8_t capabilities);\n/**\n * Change capabilities of the call.\n */\nint msi_change_capabilities(MSICall *call, uint8_t capabilities);\n\n#endif /* MSI_H */\n"
  },
  {
    "path": "toxav/rtp.c",
    "content": "/**  rtp.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include \"rtp.h\"\n#include \"bwcontroller.h\"\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/util.h\"\n#include \"../toxcore/Messenger.h\"\n\n#include <stdlib.h>\n#include <assert.h>\n\n\nint handle_rtp_packet (Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object);\n\n\nRTPSession *rtp_new (int payload_type, Messenger *m, uint32_t friendnumber,\n                     BWController *bwc, void *cs,\n                     int (*mcb) (void *, struct RTPMessage *))\n{\n    assert(mcb);\n    assert(cs);\n    assert(m);\n\n    RTPSession *retu = calloc(1, sizeof(RTPSession));\n\n    if (!retu) {\n        LOGGER_WARNING(\"Alloc failed! Program might misbehave!\");\n        return NULL;\n    }\n\n    retu->ssrc = random_int();\n    retu->payload_type = payload_type;\n\n    retu->m = m;\n    retu->friend_number = friendnumber;\n\n    /* Also set payload type as prefix */\n\n    retu->bwc = bwc;\n    retu->cs = cs;\n    retu->mcb = mcb;\n\n    if (-1 == rtp_allow_receiving(retu)) {\n        LOGGER_WARNING(\"Failed to start rtp receiving mode\");\n        free(retu);\n        return NULL;\n    }\n\n    return retu;\n}\nvoid rtp_kill (RTPSession *session)\n{\n    if (!session)\n        return;\n\n    LOGGER_DEBUG(\"Terminated RTP session: %p\", session);\n\n    rtp_stop_receiving (session);\n    free (session);\n}\nint rtp_allow_receiving(RTPSession *session)\n{\n    if (session == NULL)\n        return -1;\n\n    if (m_callback_rtp_packet(session->m, session->friend_number, session->payload_type,\n                              handle_rtp_packet, session) == -1) {\n        LOGGER_WARNING(\"Failed to register rtp receive handler\");\n        return -1;\n    }\n\n    LOGGER_DEBUG(\"Started receiving on session: %p\", session);\n    return 0;\n}\nint rtp_stop_receiving(RTPSession *session)\n{\n    if (session == NULL)\n        return -1;\n\n    m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, NULL, NULL);\n\n    LOGGER_DEBUG(\"Stopped receiving on session: %p\", session);\n    return 0;\n}\nint rtp_send_data (RTPSession *session, const uint8_t *data, uint16_t length)\n{\n    if (!session) {\n        LOGGER_WARNING(\"No session!\");\n        return -1;\n    }\n\n    uint8_t rdata[length + sizeof(struct RTPHeader) + 1];\n    memset(rdata, 0, sizeof(rdata));\n\n    rdata[0] = session->payload_type;\n\n    struct RTPHeader *header = (struct RTPHeader *)(rdata  + 1);\n\n    header->ve = 2;\n    header->pe = 0;\n    header->xe = 0;\n    header->cc = 0;\n\n    header->ma = 0;\n    header->pt = session->payload_type % 128;\n\n    header->sequnum = htons(session->sequnum);\n    header->timestamp = htonl(current_time_monotonic());\n    header->ssrc = htonl(session->ssrc);\n\n    header->cpart = 0;\n    header->tlen = htons(length);\n\n    if (MAX_CRYPTO_DATA_SIZE > length + sizeof(struct RTPHeader) + 1) {\n\n        /**\n         * The lenght is lesser than the maximum allowed lenght (including header)\n         * Send the packet in single piece.\n         */\n\n        memcpy(rdata + 1 + sizeof(struct RTPHeader), data, length);\n\n        if (-1 == send_custom_lossy_packet(session->m, session->friend_number, rdata, sizeof(rdata)))\n            LOGGER_WARNING(\"RTP send failed (len: %d)! std error: %s\", sizeof(rdata), strerror(errno));\n    } else {\n\n        /**\n         * The lenght is greater than the maximum allowed lenght (including header)\n         * Send the packet in multiple pieces.\n         */\n\n        uint16_t sent = 0;\n        uint16_t piece = MAX_CRYPTO_DATA_SIZE - (sizeof(struct RTPHeader) + 1);\n\n        while ((length - sent) + sizeof(struct RTPHeader) + 1 > MAX_CRYPTO_DATA_SIZE) {\n            memcpy(rdata + 1 + sizeof(struct RTPHeader), data + sent, piece);\n\n            if (-1 == send_custom_lossy_packet(session->m, session->friend_number,\n                                               rdata, piece + sizeof(struct RTPHeader) + 1))\n                LOGGER_WARNING(\"RTP send failed (len: %d)! std error: %s\",\n                               piece + sizeof(struct RTPHeader) + 1, strerror(errno));\n\n            sent += piece;\n            header->cpart = htons(sent);\n        }\n\n        /* Send remaining */\n        piece = length - sent;\n\n        if (piece) {\n            memcpy(rdata + 1 + sizeof(struct RTPHeader), data + sent, piece);\n\n            if (-1 == send_custom_lossy_packet(session->m, session->friend_number, rdata,\n                                               piece + sizeof(struct RTPHeader) + 1))\n                LOGGER_WARNING(\"RTP send failed (len: %d)! std error: %s\",\n                               piece + sizeof(struct RTPHeader) + 1, strerror(errno));\n        }\n    }\n\n    session->sequnum ++;\n    return 0;\n}\n\n\nbool chloss (const RTPSession *session, const struct RTPHeader *header)\n{\n    if (ntohl(header->timestamp) < session->rtimestamp) {\n        uint16_t hosq, lost = 0;\n\n        hosq = ntohs(header->sequnum);\n\n        lost = (hosq > session->rsequnum) ?\n               (session->rsequnum + 65535) - hosq :\n               session->rsequnum - hosq;\n\n        fprintf (stderr, \"Lost packet\\n\");\n\n        while (lost --)\n            bwc_add_lost(session->bwc , 0);\n\n        return true;\n    }\n\n    return false;\n}\nstruct RTPMessage *new_message (size_t allocate_len, const uint8_t *data, uint16_t data_length)\n{\n    assert(allocate_len >= data_length);\n\n    struct RTPMessage *msg = calloc(sizeof(struct RTPMessage) + (allocate_len - sizeof(struct RTPHeader)), 1);\n\n    msg->len = data_length - sizeof(struct RTPHeader);\n    memcpy(&msg->header, data, data_length);\n\n    msg->header.sequnum = ntohs(msg->header.sequnum);\n    msg->header.timestamp = ntohl(msg->header.timestamp);\n    msg->header.ssrc = ntohl(msg->header.ssrc);\n\n    msg->header.cpart = ntohs(msg->header.cpart);\n    msg->header.tlen = ntohs(msg->header.tlen);\n\n    return msg;\n}\nint handle_rtp_packet (Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object)\n{\n    (void) m;\n    (void) friendnumber;\n\n    RTPSession *session = object;\n\n    data ++;\n    length--;\n\n    if (!session || length < sizeof (struct RTPHeader)) {\n        LOGGER_WARNING(\"No session or invalid length of received buffer!\");\n        return -1;\n    }\n\n    const struct RTPHeader *header = (struct RTPHeader *) data;\n\n    if (header->pt != session->payload_type % 128) {\n        LOGGER_WARNING(\"Invalid payload type with the session\");\n        return -1;\n    }\n\n    if (ntohs(header->cpart) >= ntohs(header->tlen)) {\n        /* Never allow this case to happen */\n        return -1;\n    }\n\n    bwc_feed_avg(session->bwc, length);\n\n    if (ntohs(header->tlen) == length - sizeof (struct RTPHeader)) {\n        /* The message is sent in single part */\n\n        /* Only allow messages which have arrived in order;\n         * drop late messages\n         */\n        if (chloss(session, header)) {\n            return 0;\n        } else {\n            /* Message is not late; pick up the latest parameters */\n            session->rsequnum = ntohs(header->sequnum);\n            session->rtimestamp = ntohl(header->timestamp);\n        }\n\n        bwc_add_recv(session->bwc, length);\n\n        /* Invoke processing of active multiparted message */\n        if (session->mp) {\n            if (session->mcb)\n                session->mcb (session->cs, session->mp);\n            else\n                free(session->mp);\n\n            session->mp = NULL;\n        }\n\n        /* The message came in the allowed time;\n         * process it only if handler for the session is present.\n         */\n\n        if (!session->mcb)\n            return 0;\n\n        return session->mcb (session->cs, new_message(length, data, length));\n    } else {\n        /* The message is sent in multiple parts */\n\n        if (session->mp) {\n            /* There are 2 possible situations in this case:\n             *      1) being that we got the part of already processing message.\n             *      2) being that we got the part of a new/old message.\n             *\n             * We handle them differently as we only allow a single multiparted\n             * processing message\n             */\n\n            if (session->mp->header.sequnum == ntohs(header->sequnum) &&\n                    session->mp->header.timestamp == ntohl(header->timestamp)) {\n                /* First case */\n\n                /* Make sure we have enough allocated memory */\n                if (session->mp->header.tlen - session->mp->len < length - sizeof(struct RTPHeader) ||\n                        session->mp->header.tlen <= ntohs(header->cpart)) {\n                    /* There happened to be some corruption on the stream;\n                     * continue wihtout this part\n                     */\n                    return 0;\n                }\n\n                memcpy(session->mp->data + ntohs(header->cpart), data + sizeof(struct RTPHeader),\n                       length - sizeof(struct RTPHeader));\n\n                session->mp->len += length - sizeof(struct RTPHeader);\n\n                bwc_add_recv(session->bwc, length);\n\n                if (session->mp->len == session->mp->header.tlen) {\n                    /* Received a full message; now push it for the further\n                     * processing.\n                     */\n                    if (session->mcb)\n                        session->mcb (session->cs, session->mp);\n                    else\n                        free(session->mp);\n\n                    session->mp = NULL;\n                }\n            } else {\n                /* Second case */\n\n                if (session->mp->header.timestamp > ntohl(header->timestamp))\n                    /* The received message part is from the old message;\n                     * discard it.\n                     */\n                    return 0;\n\n                /* Measure missing parts of the old message */\n                bwc_add_lost(session->bwc,\n                             (session->mp->header.tlen - session->mp->len) +\n\n                             /* Must account sizes of rtp headers too */\n                             ((session->mp->header.tlen - session->mp->len) /\n                              MAX_CRYPTO_DATA_SIZE) * sizeof(struct RTPHeader) );\n\n                /* Push the previous message for processing */\n                if (session->mcb)\n                    session->mcb (session->cs, session->mp);\n                else\n                    free(session->mp);\n\n                session->mp = NULL;\n                goto NEW_MULTIPARTED;\n            }\n        } else {\n            /* In this case threat the message as if it was received in order\n             */\n\n            /* This is also a point for new multiparted messages */\nNEW_MULTIPARTED:\n\n            /* Only allow messages which have arrived in order;\n             * drop late messages\n             */\n            if (chloss(session, header)) {\n                return 0;\n            } else {\n                /* Message is not late; pick up the latest parameters */\n                session->rsequnum = ntohs(header->sequnum);\n                session->rtimestamp = ntohl(header->timestamp);\n            }\n\n            bwc_add_recv(session->bwc, length);\n\n            /* Again, only store message if handler is present\n             */\n            if (session->mcb) {\n                session->mp = new_message(ntohs(header->tlen) + sizeof(struct RTPHeader), data, length);\n\n                /* Reposition data if necessary */\n                if (ntohs(header->cpart));\n\n                memmove(session->mp->data + ntohs(header->cpart), session->mp->data, session->mp->len);\n            }\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "toxav/rtp.h",
    "content": "/**  rtp.h\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef RTP_H\n#define RTP_H\n\n#include \"bwcontroller.h\"\n#include \"../toxcore/Messenger.h\"\n#include \"stdbool.h\"\n\n/**\n * Payload type identifier. Also used as rtp callback prefix.\n */\nenum {\n    rtp_TypeAudio = 192,\n    rtp_TypeVideo,\n};\n\nstruct RTPHeader {\n    /* Standard RTP header */\n#ifndef WORDS_BIGENDIAN\n    uint16_t cc: 4; /* Contributing sources count */\n    uint16_t xe: 1; /* Extra header */\n    uint16_t pe: 1; /* Padding */\n    uint16_t ve: 2; /* Version */\n\n    uint16_t pt: 7; /* Payload type */\n    uint16_t ma: 1; /* Marker */\n#else\n    uint16_t ve: 2; /* Version */\n    uint16_t pe: 1; /* Padding */\n    uint16_t xe: 1; /* Extra header */\n    uint16_t cc: 4; /* Contributing sources count */\n\n    uint16_t ma: 1; /* Marker */\n    uint16_t pt: 7; /* Payload type */\n#endif\n\n    uint16_t sequnum;\n    uint32_t timestamp;\n    uint32_t ssrc;\n    uint32_t csrc[16];\n\n    /* Non-standard TOX-specific fields */\n    uint16_t cpart;/* Data offset of the current part */\n    uint16_t tlen; /* Total message lenght */\n} __attribute__ ((packed));\n\n/* Check alignment */\ntypedef char __fail_if_misaligned_1 [ sizeof(struct RTPHeader) == 80 ? 1 : -1 ];\n\nstruct RTPMessage {\n    uint16_t len;\n\n    struct RTPHeader header;\n    uint8_t data[];\n} __attribute__ ((packed));\n\n/* Check alignment */\ntypedef char __fail_if_misaligned_2 [ sizeof(struct RTPMessage) == 82 ? 1 : -1 ];\n\n/**\n * RTP control session.\n */\ntypedef struct {\n    uint8_t  payload_type;\n    uint16_t sequnum;      /* Sending sequence number */\n    uint16_t rsequnum;     /* Receiving sequence number */\n    uint32_t rtimestamp;\n    uint32_t ssrc;\n\n    struct RTPMessage *mp; /* Expected parted message */\n\n    Messenger *m;\n    uint32_t friend_number;\n\n    BWController *bwc;\n    void *cs;\n    int (*mcb) (void *, struct RTPMessage *msg);\n} RTPSession;\n\n\nRTPSession *rtp_new (int payload_type, Messenger *m, uint32_t friend_num,\n                     BWController *bwc, void *cs,\n                     int (*mcb) (void *, struct RTPMessage *));\nvoid rtp_kill (RTPSession *session);\nint rtp_allow_receiving (RTPSession *session);\nint rtp_stop_receiving (RTPSession *session);\nint rtp_send_data (RTPSession *session, const uint8_t *data, uint16_t length);\n\n#endif /* RTP_H */\n"
  },
  {
    "path": "toxav/toxav.c",
    "content": "/**  toxav.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include \"msi.h\"\n#include \"rtp.h\"\n\n#include \"../toxcore/Messenger.h\"\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/util.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)\n\ntypedef struct ToxAVCall_s {\n    ToxAV *av;\n\n    pthread_mutex_t mutex_audio[1];\n    PAIR(RTPSession *, ACSession *) audio;\n\n    pthread_mutex_t mutex_video[1];\n    PAIR(RTPSession *, VCSession *) video;\n\n    BWController *bwc;\n\n    bool active;\n    MSICall *msi_call;\n    uint32_t friend_number;\n\n    uint32_t audio_bit_rate; /* Sending audio bit rate */\n    uint32_t video_bit_rate; /* Sending video bit rate */\n\n    /** Required for monitoring changes in states */\n    uint8_t previous_self_capabilities;\n\n    pthread_mutex_t mutex[1];\n\n    struct ToxAVCall_s *prev;\n    struct ToxAVCall_s *next;\n} ToxAVCall;\n\nstruct ToxAV {\n    Messenger *m;\n    MSISession *msi;\n\n    /* Two-way storage: first is array of calls and second is list of calls with head and tail */\n    ToxAVCall **calls;\n    uint32_t calls_tail;\n    uint32_t calls_head;\n    pthread_mutex_t mutex[1];\n\n    PAIR(toxav_call_cb *, void *) ccb; /* Call callback */\n    PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */\n    PAIR(toxav_audio_receive_frame_cb *, void *) acb; /* Audio frame receive callback */\n    PAIR(toxav_video_receive_frame_cb *, void *) vcb; /* Video frame receive callback */\n    PAIR(toxav_bit_rate_status_cb *, void *) bcb; /* Bit rate control callback */\n\n    /** Decode time measures */\n    int32_t dmssc; /** Measure count */\n    int32_t dmsst; /** Last cycle total */\n    int32_t dmssa; /** Average decoding time in ms */\n\n    uint32_t interval; /** Calculated interval */\n};\n\nvoid callback_bwc (BWController *bwc, uint32_t friend_number, float loss, void *user_data);\n\nint callback_invite(void *toxav_inst, MSICall *call);\nint callback_start(void *toxav_inst, MSICall *call);\nint callback_end(void *toxav_inst, MSICall *call);\nint callback_error(void *toxav_inst, MSICall *call);\nint callback_capabilites(void *toxav_inst, MSICall *call);\n\nbool audio_bit_rate_invalid(uint32_t bit_rate);\nbool video_bit_rate_invalid(uint32_t bit_rate);\nbool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t state);\nToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error);\nToxAVCall *call_get(ToxAV *av, uint32_t friend_number);\nToxAVCall *call_remove(ToxAVCall *call);\nbool call_prepare_transmission(ToxAVCall *call);\nvoid call_kill_transmission(ToxAVCall *call);\n\nuint32_t toxav_version_major(void)\n{\n    return TOXAV_VERSION_MAJOR;\n}\n\nuint32_t toxav_version_minor(void)\n{\n    return TOXAV_VERSION_MINOR;\n}\n\nuint32_t toxav_version_patch(void)\n{\n    return TOXAV_VERSION_PATCH;\n}\n\nbool toxav_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)\n{\n  return (TOXAV_VERSION_MAJOR == major && /* Force the major version */\n            (TOXAV_VERSION_MINOR > minor || /* Current minor version must be newer than requested  -- or -- */\n                (TOXAV_VERSION_MINOR == minor && TOXAV_VERSION_PATCH >= patch) /* the patch must be the same or newer */\n            )\n         );\n}\n\nToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)\n{\n    TOXAV_ERR_NEW rc = TOXAV_ERR_NEW_OK;\n    ToxAV *av = NULL;\n\n    if (tox == NULL) {\n        rc = TOXAV_ERR_NEW_NULL;\n        goto END;\n    }\n\n    if (((Messenger *)tox)->msi_packet) {\n        rc = TOXAV_ERR_NEW_MULTIPLE;\n        goto END;\n    }\n\n    av = calloc (sizeof(ToxAV), 1);\n\n    if (av == NULL) {\n        LOGGER_WARNING(\"Allocation failed!\");\n        rc = TOXAV_ERR_NEW_MALLOC;\n        goto END;\n    }\n\n    if (create_recursive_mutex(av->mutex) != 0) {\n        LOGGER_WARNING(\"Mutex creation failed!\");\n        rc = TOXAV_ERR_NEW_MALLOC;\n        goto END;\n    }\n\n    av->m = (Messenger *)tox;\n    av->msi = msi_new(av->m);\n\n    if (av->msi == NULL) {\n        pthread_mutex_destroy(av->mutex);\n        rc = TOXAV_ERR_NEW_MALLOC;\n        goto END;\n    }\n\n    av->interval = 200;\n    av->msi->av = av;\n\n    msi_register_callback(av->msi, callback_invite, msi_OnInvite);\n    msi_register_callback(av->msi, callback_start, msi_OnStart);\n    msi_register_callback(av->msi, callback_end, msi_OnEnd);\n    msi_register_callback(av->msi, callback_error, msi_OnError);\n    msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout);\n    msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities);\n\nEND:\n\n    if (error)\n        *error = rc;\n\n    if (rc != TOXAV_ERR_NEW_OK) {\n        free(av);\n        av = NULL;\n    }\n\n    return av;\n}\nvoid toxav_kill(ToxAV *av)\n{\n    if (av == NULL)\n        return;\n\n    pthread_mutex_lock(av->mutex);\n\n    /* To avoid possible deadlocks */\n    while (av->msi && msi_kill(av->msi) != 0) {\n        pthread_mutex_unlock(av->mutex);\n        pthread_mutex_lock(av->mutex);\n    }\n\n    /* Msi kill will hang up all calls so just clean these calls */\n    if (av->calls) {\n        ToxAVCall *it = call_get(av, av->calls_head);\n\n        while (it) {\n            call_kill_transmission(it);\n            it = call_remove(it); /* This will eventually free av->calls */\n        }\n    }\n\n    pthread_mutex_unlock(av->mutex);\n    pthread_mutex_destroy(av->mutex);\n\n    free(av);\n}\nTox *toxav_get_tox(const ToxAV *av)\n{\n    return (Tox *) av->m;\n}\nuint32_t toxav_iteration_interval(const ToxAV *av)\n{\n    /* If no call is active interval is 200 */\n    return av->calls ? av->interval : 200;\n}\nvoid toxav_iterate(ToxAV *av)\n{\n    pthread_mutex_lock(av->mutex);\n\n    if (av->calls == NULL) {\n        pthread_mutex_unlock(av->mutex);\n        return;\n    }\n\n    uint64_t start = current_time_monotonic();\n    int32_t rc = 500;\n\n    ToxAVCall *i = av->calls[av->calls_head];\n\n    for (; i; i = i->next) {\n        if (i->active) {\n            pthread_mutex_lock(i->mutex);\n            pthread_mutex_unlock(av->mutex);\n\n            ac_iterate(i->audio.second);\n            vc_iterate(i->video.second);\n\n            if (i->msi_call->self_capabilities & msi_CapRAudio &&\n                    i->msi_call->peer_capabilities & msi_CapSAudio)\n                rc = MIN(i->audio.second->lp_frame_duration, rc);\n\n            if (i->msi_call->self_capabilities & msi_CapRVideo &&\n                    i->msi_call->peer_capabilities & msi_CapSVideo)\n                rc = MIN(i->video.second->lcfd, (uint32_t) rc);\n\n            uint32_t fid = i->friend_number;\n\n            pthread_mutex_unlock(i->mutex);\n            pthread_mutex_lock(av->mutex);\n\n            /* In case this call is popped from container stop iteration */\n            if (call_get(av, fid) != i)\n                break;\n        }\n    }\n\n    pthread_mutex_unlock(av->mutex);\n\n    av->interval = rc < av->dmssa ? 0 : (rc - av->dmssa);\n    av->dmsst += current_time_monotonic() - start;\n\n    if (++av->dmssc == 3) {\n        av->dmssa = av->dmsst / 3 + 5 /* NOTE Magic Offset for precission */;\n        av->dmssc = 0;\n        av->dmsst = 0;\n    }\n}\nbool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,\n                TOXAV_ERR_CALL *error)\n{\n    TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK;\n\n    pthread_mutex_lock(av->mutex);\n\n    if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))\n            || (video_bit_rate && video_bit_rate_invalid(video_bit_rate))) {\n        rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;\n        goto END;\n    }\n\n    ToxAVCall *call = call_new(av, friend_number, &rc);\n\n    if (call == NULL)\n        goto END;\n\n    call->audio_bit_rate = audio_bit_rate;\n    call->video_bit_rate = video_bit_rate;\n\n    call->previous_self_capabilities = msi_CapRAudio | msi_CapRVideo;\n\n    call->previous_self_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0;\n    call->previous_self_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0;\n\n    if (msi_invite(av->msi, &call->msi_call, friend_number, call->previous_self_capabilities) != 0) {\n        call_remove(call);\n        rc = TOXAV_ERR_CALL_SYNC;\n        goto END;\n    }\n\n    call->msi_call->av_call = call;\n\nEND:\n    pthread_mutex_unlock(av->mutex);\n\n    if (error)\n        *error = rc;\n\n    return rc == TOXAV_ERR_CALL_OK;\n}\nvoid toxav_callback_call(ToxAV *av, toxav_call_cb *function, void *user_data)\n{\n    pthread_mutex_lock(av->mutex);\n    av->ccb.first = function;\n    av->ccb.second = user_data;\n    pthread_mutex_unlock(av->mutex);\n}\nbool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,\n                  TOXAV_ERR_ANSWER *error)\n{\n    pthread_mutex_lock(av->mutex);\n\n    TOXAV_ERR_ANSWER rc = TOXAV_ERR_ANSWER_OK;\n\n    if (m_friend_exists(av->m, friend_number) == 0) {\n        rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND;\n        goto END;\n    }\n\n    if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))\n            || (video_bit_rate && video_bit_rate_invalid(video_bit_rate))\n       ) {\n        rc = TOXAV_ERR_ANSWER_INVALID_BIT_RATE;\n        goto END;\n    }\n\n    ToxAVCall *call = call_get(av, friend_number);\n\n    if (call == NULL) {\n        rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING;\n        goto END;\n    }\n\n    if (!call_prepare_transmission(call)) {\n        rc = TOXAV_ERR_ANSWER_CODEC_INITIALIZATION;\n        goto END;\n    }\n\n    call->audio_bit_rate = audio_bit_rate;\n    call->video_bit_rate = video_bit_rate;\n\n    call->previous_self_capabilities = msi_CapRAudio | msi_CapRVideo;\n\n    call->previous_self_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0;\n    call->previous_self_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0;\n\n    if (msi_answer(call->msi_call, call->previous_self_capabilities) != 0)\n        rc = TOXAV_ERR_ANSWER_SYNC;\n\nEND:\n    pthread_mutex_unlock(av->mutex);\n\n    if (error)\n        *error = rc;\n\n    return rc == TOXAV_ERR_ANSWER_OK;\n}\nvoid toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *function, void *user_data)\n{\n    pthread_mutex_lock(av->mutex);\n    av->scb.first = function;\n    av->scb.second = user_data;\n    pthread_mutex_unlock(av->mutex);\n}\nbool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL *error)\n{\n    pthread_mutex_lock(av->mutex);\n    TOXAV_ERR_CALL_CONTROL rc = TOXAV_ERR_CALL_CONTROL_OK;\n\n    if (m_friend_exists(av->m, friend_number) == 0) {\n        rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND;\n        goto END;\n    }\n\n    ToxAVCall *call = call_get(av, friend_number);\n\n    if (call == NULL || (!call->active && control != TOXAV_CALL_CONTROL_CANCEL)) {\n        rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;\n        goto END;\n    }\n\n    switch (control) {\n        case TOXAV_CALL_CONTROL_RESUME: {\n            /* Only act if paused and had media transfer active before */\n            if (call->msi_call->self_capabilities == 0 &&\n                    call->previous_self_capabilities) {\n\n                if (msi_change_capabilities(call->msi_call,\n                                            call->previous_self_capabilities) == -1) {\n                    rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                    goto END;\n                }\n\n                rtp_allow_receiving(call->audio.first);\n                rtp_allow_receiving(call->video.first);\n            } else {\n                rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;\n                goto END;\n            }\n        }\n        break;\n\n        case TOXAV_CALL_CONTROL_PAUSE: {\n            /* Only act if not already paused */\n            if (call->msi_call->self_capabilities) {\n                call->previous_self_capabilities = call->msi_call->self_capabilities;\n\n                if (msi_change_capabilities(call->msi_call, 0) == -1) {\n                    rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                    goto END;\n                }\n\n                rtp_stop_receiving(call->audio.first);\n                rtp_stop_receiving(call->video.first);\n            } else {\n                rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;\n                goto END;\n            }\n        }\n        break;\n\n        case TOXAV_CALL_CONTROL_CANCEL: {\n            /* Hang up */\n            pthread_mutex_lock(call->mutex);\n\n            if (msi_hangup(call->msi_call) != 0) {\n                rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                pthread_mutex_unlock(call->mutex);\n                goto END;\n            }\n\n            call->msi_call = NULL;\n            pthread_mutex_unlock(call->mutex);\n\n            /* No mather the case, terminate the call */\n            call_kill_transmission(call);\n            call_remove(call);\n        }\n        break;\n\n        case TOXAV_CALL_CONTROL_MUTE_AUDIO: {\n            if (call->msi_call->self_capabilities & msi_CapRAudio) {\n                if (msi_change_capabilities(call->msi_call, call->\n                                            msi_call->self_capabilities ^ msi_CapRAudio) == -1) {\n                    rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                    goto END;\n                }\n\n                rtp_stop_receiving(call->audio.first);\n            } else {\n                rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;\n                goto END;\n            }\n        }\n        break;\n\n        case TOXAV_CALL_CONTROL_UNMUTE_AUDIO: {\n            if (call->msi_call->self_capabilities ^ msi_CapRAudio) {\n                if (msi_change_capabilities(call->msi_call, call->\n                                            msi_call->self_capabilities | msi_CapRAudio) == -1) {\n                    rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                    goto END;\n                }\n\n                rtp_allow_receiving(call->audio.first);\n            } else {\n                rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;\n                goto END;\n            }\n        }\n        break;\n\n        case TOXAV_CALL_CONTROL_HIDE_VIDEO: {\n            if (call->msi_call->self_capabilities & msi_CapRVideo) {\n                if (msi_change_capabilities(call->msi_call, call->\n                                            msi_call->self_capabilities ^ msi_CapRVideo) == -1) {\n                    rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                    goto END;\n                }\n\n                rtp_stop_receiving(call->video.first);\n            } else {\n                rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;\n                goto END;\n            }\n        }\n        break;\n\n        case TOXAV_CALL_CONTROL_SHOW_VIDEO: {\n            if (call->msi_call->self_capabilities ^ msi_CapRVideo) {\n                if (msi_change_capabilities(call->msi_call, call->\n                                            msi_call->self_capabilities | msi_CapRVideo) == -1) {\n                    rc = TOXAV_ERR_CALL_CONTROL_SYNC;\n                    goto END;\n                }\n\n                rtp_allow_receiving(call->video.first);\n            } else {\n                rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;\n                goto END;\n            }\n        }\n        break;\n    }\n\nEND:\n    pthread_mutex_unlock(av->mutex);\n\n    if (error)\n        *error = rc;\n\n    return rc == TOXAV_ERR_CALL_CONTROL_OK;\n}\nbool toxav_bit_rate_set(ToxAV *av, uint32_t friend_number, int32_t audio_bit_rate,\n                        int32_t video_bit_rate, TOXAV_ERR_BIT_RATE_SET *error)\n{\n    TOXAV_ERR_BIT_RATE_SET rc = TOXAV_ERR_BIT_RATE_SET_OK;\n    ToxAVCall *call;\n\n    if (m_friend_exists(av->m, friend_number) == 0) {\n        rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND;\n        goto END;\n    }\n\n    if (audio_bit_rate > 0 && audio_bit_rate_invalid(audio_bit_rate)) {\n        rc = TOXAV_ERR_BIT_RATE_SET_INVALID_AUDIO_BIT_RATE;\n        goto END;\n    }\n\n    if (video_bit_rate > 0 && video_bit_rate_invalid(video_bit_rate)) {\n        rc = TOXAV_ERR_BIT_RATE_SET_INVALID_VIDEO_BIT_RATE;\n        goto END;\n    }\n\n    pthread_mutex_lock(av->mutex);\n    call = call_get(av, friend_number);\n\n    if (call == NULL || !call->active || call->msi_call->state != msi_CallActive) {\n        pthread_mutex_unlock(av->mutex);\n        rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL;\n        goto END;\n    }\n\n    if (audio_bit_rate >= 0) {\n        LOGGER_DEBUG(\"Setting new audio bitrate to: %d\", audio_bit_rate);\n\n        if (call->audio_bit_rate == audio_bit_rate) {\n            LOGGER_DEBUG(\"Audio bitrate already set to: %d\", audio_bit_rate);\n        } else if (audio_bit_rate == 0) {\n            LOGGER_DEBUG(\"Turned off audio sending\");\n\n            if (msi_change_capabilities(call->msi_call, call->msi_call->\n                                        self_capabilities ^ msi_CapSAudio) != 0) {\n                pthread_mutex_unlock(av->mutex);\n                rc = TOXAV_ERR_BIT_RATE_SET_SYNC;\n                goto END;\n            }\n\n            /* Audio sending is turned off; notify peer */\n            call->audio_bit_rate = 0;\n        } else {\n            pthread_mutex_lock(call->mutex);\n\n            if (call->audio_bit_rate == 0) {\n                LOGGER_DEBUG(\"Turned on audio sending\");\n\n                /* The audio has been turned off before this */\n                if (msi_change_capabilities(call->msi_call, call->\n                                            msi_call->self_capabilities | msi_CapSAudio) != 0) {\n                    pthread_mutex_unlock(call->mutex);\n                    pthread_mutex_unlock(av->mutex);\n                    rc = TOXAV_ERR_BIT_RATE_SET_SYNC;\n                    goto END;\n                }\n            } else\n                LOGGER_DEBUG(\"Set new audio bit rate %d\", audio_bit_rate);\n\n            call->audio_bit_rate = audio_bit_rate;\n            pthread_mutex_unlock(call->mutex);\n        }\n    }\n\n    if (video_bit_rate >= 0) {\n        LOGGER_DEBUG(\"Setting new video bitrate to: %d\", video_bit_rate);\n\n        if (call->video_bit_rate == video_bit_rate) {\n            LOGGER_DEBUG(\"Video bitrate already set to: %d\", video_bit_rate);\n        } else if (video_bit_rate == 0) {\n            LOGGER_DEBUG(\"Turned off video sending\");\n\n            /* Video sending is turned off; notify peer */\n            if (msi_change_capabilities(call->msi_call, call->msi_call->\n                                        self_capabilities ^ msi_CapSVideo) != 0) {\n                pthread_mutex_unlock(av->mutex);\n                rc = TOXAV_ERR_BIT_RATE_SET_SYNC;\n                goto END;\n            }\n\n            call->video_bit_rate = 0;\n        } else {\n            pthread_mutex_lock(call->mutex);\n\n            if (call->video_bit_rate == 0) {\n                LOGGER_DEBUG(\"Turned on video sending\");\n\n                /* The video has been turned off before this */\n                if (msi_change_capabilities(call->msi_call, call->\n                                            msi_call->self_capabilities | msi_CapSVideo) != 0) {\n                    pthread_mutex_unlock(call->mutex);\n                    pthread_mutex_unlock(av->mutex);\n                    rc = TOXAV_ERR_BIT_RATE_SET_SYNC;\n                    goto END;\n                }\n            } else\n                LOGGER_DEBUG(\"Set new video bit rate %d\", video_bit_rate);\n\n            call->video_bit_rate = video_bit_rate;\n            pthread_mutex_unlock(call->mutex);\n        }\n    }\n\n    pthread_mutex_unlock(av->mutex);\nEND:\n\n    if (error)\n        *error = rc;\n\n    return rc == TOXAV_ERR_BIT_RATE_SET_OK;\n}\nvoid toxav_callback_bit_rate_status(ToxAV *av, toxav_bit_rate_status_cb *function, void *user_data)\n{\n    pthread_mutex_lock(av->mutex);\n    av->bcb.first = function;\n    av->bcb.second = user_data;\n    pthread_mutex_unlock(av->mutex);\n}\nbool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count,\n                            uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME *error)\n{\n    TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;\n    ToxAVCall *call;\n\n    if (m_friend_exists(av->m, friend_number) == 0) {\n        rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;\n        goto END;\n    }\n\n    if (pthread_mutex_trylock(av->mutex) != 0) {\n        rc = TOXAV_ERR_SEND_FRAME_SYNC;\n        goto END;\n    }\n\n    call = call_get(av, friend_number);\n\n    if (call == NULL || !call->active || call->msi_call->state != msi_CallActive) {\n        pthread_mutex_unlock(av->mutex);\n        rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL;\n        goto END;\n    }\n\n    if (call->audio_bit_rate == 0 ||\n            !(call->msi_call->self_capabilities & msi_CapSAudio) ||\n            !(call->msi_call->peer_capabilities & msi_CapRAudio)) {\n        pthread_mutex_unlock(av->mutex);\n        rc = TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED;\n        goto END;\n    }\n\n    pthread_mutex_lock(call->mutex_audio);\n    pthread_mutex_unlock(av->mutex);\n\n    if (pcm == NULL) {\n        pthread_mutex_unlock(call->mutex_audio);\n        rc = TOXAV_ERR_SEND_FRAME_NULL;\n        goto END;\n    }\n\n    if (channels > 2) {\n        pthread_mutex_unlock(call->mutex_audio);\n        rc = TOXAV_ERR_SEND_FRAME_INVALID;\n        goto END;\n    }\n\n    { /* Encode and send */\n        if (ac_reconfigure_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {\n            pthread_mutex_unlock(call->mutex_audio);\n            rc = TOXAV_ERR_SEND_FRAME_INVALID;\n            goto END;\n        }\n\n        uint8_t dest[sample_count + sizeof(sampling_rate)]; /* This is more than enough always */\n\n        sampling_rate = htonl(sampling_rate);\n        memcpy(dest, &sampling_rate, sizeof(sampling_rate));\n        int vrc = opus_encode(call->audio.second->encoder, pcm, sample_count,\n                              dest + sizeof(sampling_rate), sizeof(dest) - sizeof(sampling_rate));\n\n        if (vrc < 0) {\n            LOGGER_WARNING(\"Failed to encode frame %s\", opus_strerror(vrc));\n            pthread_mutex_unlock(call->mutex_audio);\n            rc = TOXAV_ERR_SEND_FRAME_INVALID;\n            goto END;\n        }\n\n        if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate)) != 0) {\n            LOGGER_WARNING(\"Failed to send audio packet\");\n            rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;\n        }\n    }\n\n\n    pthread_mutex_unlock(call->mutex_audio);\n\nEND:\n\n    if (error)\n        *error = rc;\n\n    return rc == TOXAV_ERR_SEND_FRAME_OK;\n}\nbool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y,\n                            const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error)\n{\n    TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;\n    ToxAVCall *call;\n\n    if (m_friend_exists(av->m, friend_number) == 0) {\n        rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;\n        goto END;\n    }\n\n    if (pthread_mutex_trylock(av->mutex) != 0) {\n        rc = TOXAV_ERR_SEND_FRAME_SYNC;\n        goto END;\n    }\n\n    call = call_get(av, friend_number);\n\n    if (call == NULL || !call->active || call->msi_call->state != msi_CallActive) {\n        pthread_mutex_unlock(av->mutex);\n        rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL;\n        goto END;\n    }\n\n    if (call->video_bit_rate == 0 ||\n            !(call->msi_call->self_capabilities & msi_CapSVideo) ||\n            !(call->msi_call->peer_capabilities & msi_CapRVideo)) {\n        pthread_mutex_unlock(av->mutex);\n        rc = TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED;\n        goto END;\n    }\n\n    pthread_mutex_lock(call->mutex_video);\n    pthread_mutex_unlock(av->mutex);\n\n    if (y == NULL || u == NULL || v == NULL) {\n        pthread_mutex_unlock(call->mutex_video);\n        rc = TOXAV_ERR_SEND_FRAME_NULL;\n        goto END;\n    }\n\n    if (vc_reconfigure_encoder(call->video.second, call->video_bit_rate * 1000, width, height) != 0) {\n        pthread_mutex_unlock(call->mutex_video);\n        rc = TOXAV_ERR_SEND_FRAME_INVALID;\n        goto END;\n    }\n\n    { /* Encode */\n        vpx_image_t img;\n        img.w = img.h = img.d_w = img.d_h = 0;\n        vpx_img_alloc(&img, VPX_IMG_FMT_I420, width, height, 0);\n\n        /* I420 \"It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes.\"\n         * http://fourcc.org/yuv.php#IYUV\n         */\n        memcpy(img.planes[VPX_PLANE_Y], y, width * height);\n        memcpy(img.planes[VPX_PLANE_U], u, (width / 2) * (height / 2));\n        memcpy(img.planes[VPX_PLANE_V], v, (width / 2) * (height / 2));\n\n        int vrc = vpx_codec_encode(call->video.second->encoder, &img,\n                                   call->video.second->frame_counter, 1, 0, MAX_ENCODE_TIME_US);\n\n        vpx_img_free(&img);\n\n        if (vrc != VPX_CODEC_OK) {\n            pthread_mutex_unlock(call->mutex_video);\n            LOGGER_ERROR(\"Could not encode video frame: %s\\n\", vpx_codec_err_to_string(vrc));\n            rc = TOXAV_ERR_SEND_FRAME_INVALID;\n            goto END;\n        }\n    }\n\n    ++call->video.second->frame_counter;\n\n    { /* Send frames */\n        vpx_codec_iter_t iter = NULL;\n        const vpx_codec_cx_pkt_t *pkt;\n\n        while ((pkt = vpx_codec_get_cx_data(call->video.second->encoder, &iter))) {\n            if (pkt->kind == VPX_CODEC_CX_FRAME_PKT &&\n                    rtp_send_data(call->video.first, pkt->data.frame.buf, pkt->data.frame.sz) < 0) {\n\n                pthread_mutex_unlock(call->mutex_video);\n                LOGGER_WARNING(\"Could not send video frame: %s\\n\", strerror(errno));\n                rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;\n                goto END;\n            }\n        }\n    }\n\n    pthread_mutex_unlock(call->mutex_video);\n\nEND:\n\n    if (error)\n        *error = rc;\n\n    return rc == TOXAV_ERR_SEND_FRAME_OK;\n}\nvoid toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb *function, void *user_data)\n{\n    pthread_mutex_lock(av->mutex);\n    av->acb.first = function;\n    av->acb.second = user_data;\n    pthread_mutex_unlock(av->mutex);\n}\nvoid toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb *function, void *user_data)\n{\n    pthread_mutex_lock(av->mutex);\n    av->vcb.first = function;\n    av->vcb.second = user_data;\n    pthread_mutex_unlock(av->mutex);\n}\n\n\n/*******************************************************************************\n *\n * :: Internal\n *\n ******************************************************************************/\nvoid callback_bwc(BWController *bwc, uint32_t friend_number, float loss, void *user_data)\n{\n    /* Callback which is called when the internal measure mechanism reported packet loss.\n     * We report suggested lowered bitrate to an app. If app is sending both audio and video,\n     * we will report lowered bitrate for video only because in that case video probably\n     * takes more than 90% bandwidth. Otherwise, we report lowered bitrate on audio.\n     * The application may choose to disable video totally if the stream is too bad.\n     */\n\n    ToxAVCall *call = user_data;\n    assert(call);\n\n    LOGGER_DEBUG(\"Reported loss of %f%%\", loss * 100);\n\n    if (loss < .01f)\n        return;\n\n    pthread_mutex_lock(call->av->mutex);\n\n    if (!call->av->bcb.first) {\n        pthread_mutex_unlock(call->av->mutex);\n        LOGGER_WARNING(\"No callback to report loss on\");\n        return;\n    }\n\n    if (call->video_bit_rate)\n        (*call->av->bcb.first) (call->av, friend_number, call->audio_bit_rate,\n                                call->video_bit_rate - (call->video_bit_rate * loss),\n                                call->av->bcb.second);\n    else if (call->audio_bit_rate)\n        (*call->av->bcb.first) (call->av, friend_number,\n                                call->audio_bit_rate - (call->audio_bit_rate * loss),\n                                0, call->av->bcb.second);\n\n    pthread_mutex_unlock(call->av->mutex);\n}\nint callback_invite(void *toxav_inst, MSICall *call)\n{\n    ToxAV *toxav = toxav_inst;\n    pthread_mutex_lock(toxav->mutex);\n\n    ToxAVCall *av_call = call_new(toxav, call->friend_number, NULL);\n\n    if (av_call == NULL) {\n        LOGGER_WARNING(\"Failed to initialize call...\");\n        pthread_mutex_unlock(toxav->mutex);\n        return -1;\n    }\n\n    call->av_call = av_call;\n    av_call->msi_call = call;\n\n    if (toxav->ccb.first)\n        toxav->ccb.first(toxav, call->friend_number, call->peer_capabilities & msi_CapSAudio,\n                         call->peer_capabilities & msi_CapSVideo, toxav->ccb.second);\n    else {\n        /* No handler to capture the call request, send failure */\n        pthread_mutex_unlock(toxav->mutex);\n        return -1;\n    }\n\n    pthread_mutex_unlock(toxav->mutex);\n    return 0;\n}\nint callback_start(void *toxav_inst, MSICall *call)\n{\n    ToxAV *toxav = toxav_inst;\n    pthread_mutex_lock(toxav->mutex);\n\n    ToxAVCall *av_call = call_get(toxav, call->friend_number);\n\n    if (av_call == NULL) {\n        /* Should this ever happen? */\n        pthread_mutex_unlock(toxav->mutex);\n        return -1;\n    }\n\n    if (!call_prepare_transmission(av_call)) {\n        callback_error(toxav_inst, call);\n        pthread_mutex_unlock(toxav->mutex);\n        return -1;\n    }\n\n    if (!invoke_call_state_callback(toxav, call->friend_number, call->peer_capabilities)) {\n        callback_error(toxav_inst, call);\n        pthread_mutex_unlock(toxav->mutex);\n        return -1;\n    }\n\n    pthread_mutex_unlock(toxav->mutex);\n    return 0;\n}\nint callback_end(void *toxav_inst, MSICall *call)\n{\n    ToxAV *toxav = toxav_inst;\n    pthread_mutex_lock(toxav->mutex);\n\n    invoke_call_state_callback(toxav, call->friend_number, TOXAV_FRIEND_CALL_STATE_FINISHED);\n\n    if (call->av_call) {\n        call_kill_transmission(call->av_call);\n        call_remove(call->av_call);\n    }\n\n    pthread_mutex_unlock(toxav->mutex);\n    return 0;\n}\nint callback_error(void *toxav_inst, MSICall *call)\n{\n    ToxAV *toxav = toxav_inst;\n    pthread_mutex_lock(toxav->mutex);\n\n    invoke_call_state_callback(toxav, call->friend_number, TOXAV_FRIEND_CALL_STATE_ERROR);\n\n    if (call->av_call) {\n        call_kill_transmission(call->av_call);\n        call_remove(call->av_call);\n    }\n\n    pthread_mutex_unlock(toxav->mutex);\n    return 0;\n}\nint callback_capabilites(void *toxav_inst, MSICall *call)\n{\n    ToxAV *toxav = toxav_inst;\n    pthread_mutex_lock(toxav->mutex);\n\n    if (call->peer_capabilities & msi_CapSAudio)\n        rtp_allow_receiving(((ToxAVCall *)call->av_call)->audio.first);\n    else\n        rtp_stop_receiving(((ToxAVCall *)call->av_call)->audio.first);\n\n    if (call->peer_capabilities & msi_CapSVideo)\n        rtp_allow_receiving(((ToxAVCall *)call->av_call)->video.first);\n    else\n        rtp_stop_receiving(((ToxAVCall *)call->av_call)->video.first);\n\n    invoke_call_state_callback(toxav, call->friend_number, call->peer_capabilities);\n\n    pthread_mutex_unlock(toxav->mutex);\n    return 0;\n}\nbool audio_bit_rate_invalid(uint32_t bit_rate)\n{\n    /* Opus RFC 6716 section-2.1.1 dictates the following:\n     * Opus supports all bit rates from 6 kbit/s to 510 kbit/s.\n     */\n    return bit_rate < 6 || bit_rate > 510;\n}\nbool video_bit_rate_invalid(uint32_t bit_rate)\n{\n    (void) bit_rate;\n    /* TODO: If anyone knows the answer to this one please fill it up */\n    return false;\n}\nbool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t state)\n{\n    if (av->scb.first)\n        av->scb.first(av, friend_number, state, av->scb.second);\n    else\n        return false;\n\n    return true;\n}\nToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error)\n{\n    /* Assumes mutex locked */\n    TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK;\n    ToxAVCall *call = NULL;\n\n    if (m_friend_exists(av->m, friend_number) == 0) {\n        rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND;\n        goto END;\n    }\n\n    if (m_get_friend_connectionstatus(av->m, friend_number) < 1) {\n        rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED;\n        goto END;\n    }\n\n    if (call_get(av, friend_number) != NULL) {\n        rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL;\n        goto END;\n    }\n\n\n    call = calloc(sizeof(ToxAVCall), 1);\n\n    if (call == NULL) {\n        rc = TOXAV_ERR_CALL_MALLOC;\n        goto END;\n    }\n\n    call->av = av;\n    call->friend_number = friend_number;\n\n    if (av->calls == NULL) { /* Creating */\n        av->calls = calloc (sizeof(ToxAVCall *), friend_number + 1);\n\n        if (av->calls == NULL) {\n            free(call);\n            call = NULL;\n            rc = TOXAV_ERR_CALL_MALLOC;\n            goto END;\n        }\n\n        av->calls_tail = av->calls_head = friend_number;\n\n    } else if (av->calls_tail < friend_number) { /* Appending */\n        void *tmp = realloc(av->calls, sizeof(ToxAVCall *) * (friend_number + 1));\n\n        if (tmp == NULL) {\n            free(call);\n            call = NULL;\n            rc = TOXAV_ERR_CALL_MALLOC;\n            goto END;\n        }\n\n        av->calls = tmp;\n\n        /* Set fields in between to null */\n        uint32_t i = av->calls_tail + 1;\n\n        for (; i < friend_number; i ++)\n            av->calls[i] = NULL;\n\n        call->prev = av->calls[av->calls_tail];\n        av->calls[av->calls_tail]->next = call;\n\n        av->calls_tail = friend_number;\n\n    } else if (av->calls_head > friend_number) { /* Inserting at front */\n        call->next = av->calls[av->calls_head];\n        av->calls[av->calls_head]->prev = call;\n        av->calls_head = friend_number;\n    }\n\n    av->calls[friend_number] = call;\n\nEND:\n\n    if (error)\n        *error = rc;\n\n    return call;\n}\nToxAVCall *call_get(ToxAV *av, uint32_t friend_number)\n{\n    /* Assumes mutex locked */\n    if (av->calls == NULL || av->calls_tail < friend_number)\n        return NULL;\n\n    return av->calls[friend_number];\n}\nToxAVCall *call_remove(ToxAVCall *call)\n{\n    if (call == NULL)\n        return NULL;\n\n    uint32_t friend_number = call->friend_number;\n    ToxAV *av = call->av;\n\n    ToxAVCall *prev = call->prev;\n    ToxAVCall *next = call->next;\n\n    /* Set av call in msi to NULL in order to know if call if ToxAVCall is\n     * removed from the msi call.\n     */\n    if (call->msi_call) {\n        call->msi_call->av_call = NULL;\n    }\n\n    free(call);\n\n    if (prev)\n        prev->next = next;\n    else if (next)\n        av->calls_head = next->friend_number;\n    else goto CLEAR;\n\n    if (next)\n        next->prev = prev;\n    else if (prev)\n        av->calls_tail = prev->friend_number;\n    else goto CLEAR;\n\n    av->calls[friend_number] = NULL;\n    return next;\n\nCLEAR:\n    av->calls_head = av->calls_tail = 0;\n    free(av->calls);\n    av->calls = NULL;\n\n    return NULL;\n}\nbool call_prepare_transmission(ToxAVCall *call)\n{\n    /* Assumes mutex locked */\n\n    if (call == NULL)\n        return false;\n\n    ToxAV *av = call->av;\n\n    if (!av->acb.first && !av->vcb.first)\n        /* It makes no sense to have CSession without callbacks */\n        return false;\n\n    if (call->active) {\n        LOGGER_WARNING(\"Call already active!\\n\");\n        return true;\n    }\n\n    if (create_recursive_mutex(call->mutex_audio) != 0)\n        return false;\n\n    if (create_recursive_mutex(call->mutex_video) != 0)\n        goto FAILURE_3;\n\n    if (create_recursive_mutex(call->mutex) != 0)\n        goto FAILURE_2;\n\n    /* Prepare bwc */\n    call->bwc = bwc_new(av->m, call->friend_number, callback_bwc, call);\n\n    { /* Prepare audio */\n        call->audio.second = ac_new(av, call->friend_number, av->acb.first, av->acb.second);\n\n        if (!call->audio.second) {\n            LOGGER_ERROR(\"Failed to create audio codec session\");\n            goto FAILURE;\n        }\n\n        call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_number, call->bwc,\n                                    call->audio.second, ac_queue_message);\n\n        if (!call->audio.first) {\n            LOGGER_ERROR(\"Failed to create audio rtp session\");;\n            goto FAILURE;\n        }\n    }\n    { /* Prepare video */\n        call->video.second = vc_new(av, call->friend_number, av->vcb.first, av->vcb.second);\n\n        if (!call->video.second) {\n            LOGGER_ERROR(\"Failed to create video codec session\");\n            goto FAILURE;\n        }\n\n        call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_number, call->bwc,\n                                    call->video.second, vc_queue_message);\n\n        if (!call->video.first) {\n            LOGGER_ERROR(\"Failed to create video rtp session\");\n            goto FAILURE;\n        }\n    }\n\n    call->active = 1;\n    return true;\n\nFAILURE:\n    bwc_kill(call->bwc);\n    rtp_kill(call->audio.first);\n    ac_kill(call->audio.second);\n    call->audio.first = NULL;\n    call->audio.second = NULL;\n    rtp_kill(call->video.first);\n    vc_kill(call->video.second);\n    call->video.first = NULL;\n    call->video.second = NULL;\n    pthread_mutex_destroy(call->mutex);\nFAILURE_2:\n    pthread_mutex_destroy(call->mutex_video);\nFAILURE_3:\n    pthread_mutex_destroy(call->mutex_audio);\n    return false;\n}\nvoid call_kill_transmission(ToxAVCall *call)\n{\n    if (call == NULL || call->active == 0)\n        return;\n\n    call->active = 0;\n\n    pthread_mutex_lock(call->mutex_audio);\n    pthread_mutex_unlock(call->mutex_audio);\n    pthread_mutex_lock(call->mutex_video);\n    pthread_mutex_unlock(call->mutex_video);\n    pthread_mutex_lock(call->mutex);\n    pthread_mutex_unlock(call->mutex);\n\n    bwc_kill(call->bwc);\n\n    rtp_kill(call->audio.first);\n    ac_kill(call->audio.second);\n    call->audio.first = NULL;\n    call->audio.second = NULL;\n\n    rtp_kill(call->video.first);\n    vc_kill(call->video.second);\n    call->video.first = NULL;\n    call->video.second = NULL;\n\n    pthread_mutex_destroy(call->mutex_audio);\n    pthread_mutex_destroy(call->mutex_video);\n    pthread_mutex_destroy(call->mutex);\n}\n"
  },
  {
    "path": "toxav/toxav.h",
    "content": "/* toxav.h\n *\n * Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n * This file is part of Tox.\n *\n * Tox is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Tox is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TOXAV_H\n#define TOXAV_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** \\page av Public audio/video API for Tox clients.\n *\n * This API can handle multiple calls. Each call has its state, in very rare\n * occasions the library can change the state of the call without apps knowledge.\n *\n */\n/** \\subsection events Events and callbacks\n *\n * As in Core API, events are handled by callbacks. One callback can be\n * registered per event. All events have a callback function type named\n * `toxav_{event}_cb` and a function to register it named `toxav_callback_{event}`.\n * Passing a NULL callback will result in no callback being registered for that\n * event. Only one callback per event can be registered, so if a client needs\n * multiple event listeners, it needs to implement the dispatch functionality\n * itself. Unlike Core API, lack of some event handlers will cause the the\n * library to drop calls before they are started. Hanging up call from a\n * callback causes undefined behaviour.\n *\n */\n/** \\subsection threading Threading implications\n *\n * Unlike the Core API, this API is fully thread-safe. The library will ensure\n * the proper synchronization of parallel calls.\n *\n * A common way to run ToxAV (multiple or single instance) is to have a thread,\n * separate from tox instance thread, running a simple toxav_iterate loop,\n * sleeping for toxav_iteration_interval * milliseconds on each iteration.\n *\n * An important thing to note is that events are triggered from both tox and\n * toxav thread (see above). Audio and video receive frame events are triggered\n * from toxav thread while all the other events are triggered from tox thread.\n *\n * Tox thread has priority with mutex mechanisms. Any api function can\n * fail if mutexes are held by tox thread in which case they will set SYNC\n * error code.\n */\n/**\n * External Tox type.\n */\n#ifndef TOX_DEFINED\n#define TOX_DEFINED\ntypedef struct Tox Tox;\n#endif /* TOX_DEFINED */\n\n/**\n * ToxAV.\n */\n/**\n * The ToxAV instance type. Each ToxAV instance can be bound to only one Tox\n * instance, and Tox instance can have only one ToxAV instance. One must make\n * sure to close ToxAV instance prior closing Tox instance otherwise undefined\n * behaviour occurs. Upon closing of ToxAV instance, all active calls will be\n * forcibly terminated without notifying peers.\n *\n */\n#ifndef TOXAV_DEFINED\n#define TOXAV_DEFINED\ntypedef struct ToxAV ToxAV;\n#endif /* TOXAV_DEFINED */\n\n\n/*******************************************************************************\n *\n * :: API version\n *\n ******************************************************************************/\n\n\n\n/**\n * The major version number. Incremented when the API or ABI changes in an\n * incompatible way.\n */\n#define TOXAV_VERSION_MAJOR               0u\n\n/**\n * The minor version number. Incremented when functionality is added without\n * breaking the API or ABI. Set to 0 when the major version number is\n * incremented.\n */\n#define TOXAV_VERSION_MINOR               0u\n\n/**\n * The patch or revision number. Incremented when bugfixes are applied without\n * changing any functionality or API or ABI.\n */\n#define TOXAV_VERSION_PATCH               0u\n\n/**\n * A macro to check at preprocessing time whether the client code is compatible\n * with the installed version of ToxAV.\n */\n#define TOXAV_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH)        \\\n  (TOXAV_VERSION_MAJOR == MAJOR &&                                \\\n   (TOXAV_VERSION_MINOR > MINOR ||                                \\\n    (TOXAV_VERSION_MINOR == MINOR &&                              \\\n     TOXAV_VERSION_PATCH >= PATCH)))\n\n/**\n * A macro to make compilation fail if the client code is not compatible with\n * the installed version of ToxAV.\n */\n#define TOXAV_VERSION_REQUIRE(MAJOR, MINOR, PATCH)                \\\n  typedef char toxav_required_version[TOXAV_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1]\n\n/**\n * A convenience macro to call toxav_version_is_compatible with the currently\n * compiling API version.\n */\n#define TOXAV_VERSION_IS_ABI_COMPATIBLE()                         \\\n  toxav_version_is_compatible(TOXAV_VERSION_MAJOR, TOXAV_VERSION_MINOR, TOXAV_VERSION_PATCH)\n\n/**\n * Return the major version number of the library. Can be used to display the\n * ToxAV library version or to check whether the client is compatible with the\n * dynamically linked version of ToxAV.\n */\nuint32_t toxav_version_major(void);\n\n/**\n * Return the minor version number of the library.\n */\nuint32_t toxav_version_minor(void);\n\n/**\n * Return the patch number of the library.\n */\nuint32_t toxav_version_patch(void);\n\n/**\n * Return whether the compiled library version is compatible with the passed\n * version numbers.\n */\nbool toxav_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch);\n\n\n/*******************************************************************************\n *\n * :: Creation and destruction\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOXAV_ERR_NEW {\n\n    /**\n     * The function returned successfully.\n     */\n    TOXAV_ERR_NEW_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOXAV_ERR_NEW_NULL,\n\n    /**\n     * Memory allocation failure while trying to allocate structures required for\n     * the A/V session.\n     */\n    TOXAV_ERR_NEW_MALLOC,\n\n    /**\n     * Attempted to create a second session for the same Tox instance.\n     */\n    TOXAV_ERR_NEW_MULTIPLE,\n\n} TOXAV_ERR_NEW;\n\n\n/**\n * Start new A/V session. There can only be only one session per Tox instance.\n */\nToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error);\n\n/**\n * Releases all resources associated with the A/V session.\n *\n * If any calls were ongoing, these will be forcibly terminated without\n * notifying peers. After calling this function, no other functions may be\n * called and the av pointer becomes invalid.\n */\nvoid toxav_kill(ToxAV *toxAV);\n\n/**\n * Returns the Tox instance the A/V object was created for.\n */\nTox *toxav_get_tox(const ToxAV *toxAV);\n\n\n/*******************************************************************************\n *\n * :: A/V event loop\n *\n ******************************************************************************/\n\n\n\n/**\n * Returns the interval in milliseconds when the next toxav_iterate call should\n * be. If no call is active at the moment, this function returns 200.\n */\nuint32_t toxav_iteration_interval(const ToxAV *toxAV);\n\n/**\n * Main loop for the session. This function needs to be called in intervals of\n * toxav_iteration_interval() milliseconds. It is best called in the separate\n * thread from tox_iterate.\n */\nvoid toxav_iterate(ToxAV *toxAV);\n\n\n/*******************************************************************************\n *\n * :: Call setup\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOXAV_ERR_CALL {\n\n    /**\n     * The function returned successfully.\n     */\n    TOXAV_ERR_CALL_OK,\n\n    /**\n     * A resource allocation error occurred while trying to create the structures\n     * required for the call.\n     */\n    TOXAV_ERR_CALL_MALLOC,\n\n    /**\n     * Synchronization error occurred.\n     */\n    TOXAV_ERR_CALL_SYNC,\n\n    /**\n     * The friend number did not designate a valid friend.\n     */\n    TOXAV_ERR_CALL_FRIEND_NOT_FOUND,\n\n    /**\n     * The friend was valid, but not currently connected.\n     */\n    TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED,\n\n    /**\n     * Attempted to call a friend while already in an audio or video call with\n     * them.\n     */\n    TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL,\n\n    /**\n     * Audio or video bit rate is invalid.\n     */\n    TOXAV_ERR_CALL_INVALID_BIT_RATE,\n\n} TOXAV_ERR_CALL;\n\n\n/**\n * Call a friend. This will start ringing the friend.\n *\n * It is the client's responsibility to stop ringing after a certain timeout,\n * if such behaviour is desired. If the client does not stop ringing, the\n * library will not stop until the friend is disconnected. Audio and video\n * receiving are both enabled by default.\n *\n * @param friend_number The friend number of the friend that should be called.\n * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable\n * audio sending.\n * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable\n * video sending.\n */\nbool toxav_call(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,\n                TOXAV_ERR_CALL *error);\n\n/**\n * The function type for the call callback.\n *\n * @param friend_number The friend number from which the call is incoming.\n * @param audio_enabled True if friend is sending audio.\n * @param video_enabled True if friend is sending video.\n */\ntypedef void toxav_call_cb(ToxAV *toxAV, uint32_t friend_number, bool audio_enabled, bool video_enabled,\n                           void *user_data);\n\n\n/**\n * Set the callback for the `call` event. Pass NULL to unset.\n *\n */\nvoid toxav_callback_call(ToxAV *toxAV, toxav_call_cb *callback, void *user_data);\n\ntypedef enum TOXAV_ERR_ANSWER {\n\n    /**\n     * The function returned successfully.\n     */\n    TOXAV_ERR_ANSWER_OK,\n\n    /**\n     * Synchronization error occurred.\n     */\n    TOXAV_ERR_ANSWER_SYNC,\n\n    /**\n     * Failed to initialize codecs for call session. Note that codec initiation\n     * will fail if there is no receive callback registered for either audio or\n     * video.\n     */\n    TOXAV_ERR_ANSWER_CODEC_INITIALIZATION,\n\n    /**\n     * The friend number did not designate a valid friend.\n     */\n    TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND,\n\n    /**\n     * The friend was valid, but they are not currently trying to initiate a call.\n     * This is also returned if this client is already in a call with the friend.\n     */\n    TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING,\n\n    /**\n     * Audio or video bit rate is invalid.\n     */\n    TOXAV_ERR_ANSWER_INVALID_BIT_RATE,\n\n} TOXAV_ERR_ANSWER;\n\n\n/**\n * Accept an incoming call.\n *\n * If answering fails for any reason, the call will still be pending and it is\n * possible to try and answer it later. Audio and video receiving are both\n * enabled by default.\n *\n * @param friend_number The friend number of the friend that is calling.\n * @param audio_bit_rate Audio bit rate in Kb/sec. Set this to 0 to disable\n * audio sending.\n * @param video_bit_rate Video bit rate in Kb/sec. Set this to 0 to disable\n * video sending.\n */\nbool toxav_answer(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,\n                  TOXAV_ERR_ANSWER *error);\n\n\n/*******************************************************************************\n *\n * :: Call state graph\n *\n ******************************************************************************/\n\n\n\nenum TOXAV_FRIEND_CALL_STATE {\n\n    /**\n     * Set by the AV core if an error occurred on the remote end or if friend\n     * timed out. This is the final state after which no more state\n     * transitions can occur for the call. This call state will never be triggered\n     * in combination with other call states.\n     */\n    TOXAV_FRIEND_CALL_STATE_ERROR = 1,\n\n    /**\n     * The call has finished. This is the final state after which no more state\n     * transitions can occur for the call. This call state will never be\n     * triggered in combination with other call states.\n     */\n    TOXAV_FRIEND_CALL_STATE_FINISHED = 2,\n\n    /**\n     * The flag that marks that friend is sending audio.\n     */\n    TOXAV_FRIEND_CALL_STATE_SENDING_A = 4,\n\n    /**\n     * The flag that marks that friend is sending video.\n     */\n    TOXAV_FRIEND_CALL_STATE_SENDING_V = 8,\n\n    /**\n     * The flag that marks that friend is receiving audio.\n     */\n    TOXAV_FRIEND_CALL_STATE_ACCEPTING_A = 16,\n\n    /**\n     * The flag that marks that friend is receiving video.\n     */\n    TOXAV_FRIEND_CALL_STATE_ACCEPTING_V = 32,\n\n};\n\n\n/**\n * The function type for the call_state callback.\n *\n * @param friend_number The friend number for which the call state changed.\n * @param state The bitmask of the new call state which is guaranteed to be\n * different than the previous state. The state is set to 0 when the call is\n * paused. The bitmask represents all the activities currently performed by the\n * friend.\n */\ntypedef void toxav_call_state_cb(ToxAV *toxAV, uint32_t friend_number, uint32_t state, void *user_data);\n\n\n/**\n * Set the callback for the `call_state` event. Pass NULL to unset.\n *\n */\nvoid toxav_callback_call_state(ToxAV *toxAV, toxav_call_state_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: Call control\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOXAV_CALL_CONTROL {\n\n    /**\n     * Resume a previously paused call. Only valid if the pause was caused by this\n     * client, if not, this control is ignored. Not valid before the call is accepted.\n     */\n    TOXAV_CALL_CONTROL_RESUME,\n\n    /**\n     * Put a call on hold. Not valid before the call is accepted.\n     */\n    TOXAV_CALL_CONTROL_PAUSE,\n\n    /**\n     * Reject a call if it was not answered, yet. Cancel a call after it was\n     * answered.\n     */\n    TOXAV_CALL_CONTROL_CANCEL,\n\n    /**\n     * Request that the friend stops sending audio. Regardless of the friend's\n     * compliance, this will cause the audio_receive_frame event to stop being\n     * triggered on receiving an audio frame from the friend.\n     */\n    TOXAV_CALL_CONTROL_MUTE_AUDIO,\n\n    /**\n     * Calling this control will notify client to start sending audio again.\n     */\n    TOXAV_CALL_CONTROL_UNMUTE_AUDIO,\n\n    /**\n     * Request that the friend stops sending video. Regardless of the friend's\n     * compliance, this will cause the video_receive_frame event to stop being\n     * triggered on receiving a video frame from the friend.\n     */\n    TOXAV_CALL_CONTROL_HIDE_VIDEO,\n\n    /**\n     * Calling this control will notify client to start sending video again.\n     */\n    TOXAV_CALL_CONTROL_SHOW_VIDEO,\n\n} TOXAV_CALL_CONTROL;\n\n\ntypedef enum TOXAV_ERR_CALL_CONTROL {\n\n    /**\n     * The function returned successfully.\n     */\n    TOXAV_ERR_CALL_CONTROL_OK,\n\n    /**\n     * Synchronization error occurred.\n     */\n    TOXAV_ERR_CALL_CONTROL_SYNC,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not in a call with the friend. Before the call is\n     * answered, only CANCEL is a valid control.\n     */\n    TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL,\n\n    /**\n     * Happens if user tried to pause an already paused call or if trying to\n     * resume a call that is not paused.\n     */\n    TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION,\n\n} TOXAV_ERR_CALL_CONTROL;\n\n\n/**\n * Sends a call control command to a friend.\n *\n * @param friend_number The friend number of the friend this client is in a call\n * with.\n * @param control The control command to send.\n *\n * @return true on success.\n */\nbool toxav_call_control(ToxAV *toxAV, uint32_t friend_number, TOXAV_CALL_CONTROL control,\n                        TOXAV_ERR_CALL_CONTROL *error);\n\n\n/*******************************************************************************\n *\n * :: Controlling bit rates\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOXAV_ERR_BIT_RATE_SET {\n\n    /**\n     * The function returned successfully.\n     */\n    TOXAV_ERR_BIT_RATE_SET_OK,\n\n    /**\n     * Synchronization error occurred.\n     */\n    TOXAV_ERR_BIT_RATE_SET_SYNC,\n\n    /**\n     * The audio bit rate passed was not one of the supported values.\n     */\n    TOXAV_ERR_BIT_RATE_SET_INVALID_AUDIO_BIT_RATE,\n\n    /**\n     * The video bit rate passed was not one of the supported values.\n     */\n    TOXAV_ERR_BIT_RATE_SET_INVALID_VIDEO_BIT_RATE,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not in a call with the friend.\n     */\n    TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL,\n\n} TOXAV_ERR_BIT_RATE_SET;\n\n\n/**\n * Set the bit rate to be used in subsequent audio/video frames.\n *\n * @param friend_number The friend number of the friend for which to set the\n * bit rate.\n * @param audio_bit_rate The new audio bit rate in Kb/sec. Set to 0 to disable\n * audio sending. Set to -1 to leave unchanged.\n * @param video_bit_rate The new video bit rate in Kb/sec. Set to 0 to disable\n * video sending. Set to -1 to leave unchanged.\n *\n */\nbool toxav_bit_rate_set(ToxAV *toxAV, uint32_t friend_number, int32_t audio_bit_rate, int32_t video_bit_rate,\n                        TOXAV_ERR_BIT_RATE_SET *error);\n\n/**\n * The function type for the bit_rate_status callback. The event is triggered\n * when the network becomes too saturated for current bit rates at which\n * point core suggests new bit rates.\n *\n * @param friend_number The friend number of the friend for which to set the\n * bit rate.\n * @param audio_bit_rate Suggested maximum audio bit rate in Kb/sec.\n * @param video_bit_rate Suggested maximum video bit rate in Kb/sec.\n */\ntypedef void toxav_bit_rate_status_cb(ToxAV *toxAV, uint32_t friend_number, uint32_t audio_bit_rate,\n                                      uint32_t video_bit_rate, void *user_data);\n\n\n/**\n * Set the callback for the `bit_rate_status` event. Pass NULL to unset.\n *\n */\nvoid toxav_callback_bit_rate_status(ToxAV *toxAV, toxav_bit_rate_status_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: A/V sending\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOXAV_ERR_SEND_FRAME {\n\n    /**\n     * The function returned successfully.\n     */\n    TOXAV_ERR_SEND_FRAME_OK,\n\n    /**\n     * In case of video, one of Y, U, or V was NULL. In case of audio, the samples\n     * data pointer was NULL.\n     */\n    TOXAV_ERR_SEND_FRAME_NULL,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not in a call with the friend.\n     */\n    TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL,\n\n    /**\n     * Synchronization error occurred.\n     */\n    TOXAV_ERR_SEND_FRAME_SYNC,\n\n    /**\n     * One of the frame parameters was invalid. E.g. the resolution may be too\n     * small or too large, or the audio sampling rate may be unsupported.\n     */\n    TOXAV_ERR_SEND_FRAME_INVALID,\n\n    /**\n     * Either friend turned off audio or video receiving or we turned off sending\n     * for the said payload.\n     */\n    TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED,\n\n    /**\n     * Failed to push frame through rtp interface.\n     */\n    TOXAV_ERR_SEND_FRAME_RTP_FAILED,\n\n} TOXAV_ERR_SEND_FRAME;\n\n\n/**\n * Send an audio frame to a friend.\n *\n * The expected format of the PCM data is: [s1c1][s1c2][...][s2c1][s2c2][...]...\n * Meaning: sample 1 for channel 1, sample 1 for channel 2, ...\n * For mono audio, this has no meaning, every sample is subsequent. For stereo,\n * this means the expected format is LRLRLR... with samples for left and right\n * alternating.\n *\n * @param friend_number The friend number of the friend to which to send an\n * audio frame.\n * @param pcm An array of audio samples. The size of this array must be\n * sample_count * channels.\n * @param sample_count Number of samples in this frame. Valid numbers here are\n * ((sample rate) * (audio length) / 1000), where audio length can be\n * 2.5, 5, 10, 20, 40 or 60 millseconds.\n * @param channels Number of audio channels. Supported values are 1 and 2.\n * @param sampling_rate Audio sampling rate used in this frame. Valid sampling\n * rates are 8000, 12000, 16000, 24000, or 48000.\n */\nbool toxav_audio_send_frame(ToxAV *toxAV, uint32_t friend_number, const int16_t *pcm, size_t sample_count,\n                            uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME *error);\n\n/**\n * Send a video frame to a friend.\n *\n * Y - plane should be of size: height * width\n * U - plane should be of size: (height/2) * (width/2)\n * V - plane should be of size: (height/2) * (width/2)\n *\n * @param friend_number The friend number of the friend to which to send a video\n * frame.\n * @param width Width of the frame in pixels.\n * @param height Height of the frame in pixels.\n * @param y Y (Luminance) plane data.\n * @param u U (Chroma) plane data.\n * @param v V (Chroma) plane data.\n */\nbool toxav_video_send_frame(ToxAV *toxAV, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y,\n                            const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error);\n\n\n/*******************************************************************************\n *\n * :: A/V receiving\n *\n ******************************************************************************/\n\n\n\n/**\n * The function type for the audio_receive_frame callback. The callback can be\n * called multiple times per single iteration depending on the amount of queued\n * frames in the buffer. The received format is the same as in send function.\n *\n * @param friend_number The friend number of the friend who sent an audio frame.\n * @param pcm An array of audio samples (sample_count * channels elements).\n * @param sample_count The number of audio samples per channel in the PCM array.\n * @param channels Number of audio channels.\n * @param sampling_rate Sampling rate used in this frame.\n *\n */\ntypedef void toxav_audio_receive_frame_cb(ToxAV *toxAV, uint32_t friend_number, const int16_t *pcm, size_t sample_count,\n        uint8_t channels, uint32_t sampling_rate, void *user_data);\n\n\n/**\n * Set the callback for the `audio_receive_frame` event. Pass NULL to unset.\n *\n */\nvoid toxav_callback_audio_receive_frame(ToxAV *toxAV, toxav_audio_receive_frame_cb *callback, void *user_data);\n\n/**\n * The function type for the video_receive_frame callback.\n *\n * @param friend_number The friend number of the friend who sent a video frame.\n * @param width Width of the frame in pixels.\n * @param height Height of the frame in pixels.\n * @param y\n * @param u\n * @param v Plane data.\n *          The size of plane data is derived from width and height where\n *          Y = MAX(width, abs(ystride)) * height,\n *          U = MAX(width/2, abs(ustride)) * (height/2) and\n *          V = MAX(width/2, abs(vstride)) * (height/2).\n * @param ystride\n * @param ustride\n * @param vstride Strides data. Strides represent padding for each plane\n *                that may or may not be present. You must handle strides in\n *                your image processing code. Strides are negative if the\n *                image is bottom-up hence why you MUST abs() it when\n *                calculating plane buffer size.\n */\ntypedef void toxav_video_receive_frame_cb(ToxAV *toxAV, uint32_t friend_number, uint16_t width, uint16_t height,\n        const uint8_t *y, const uint8_t *u, const uint8_t *v, int32_t ystride, int32_t ustride, int32_t vstride,\n        void *user_data);\n\n\n/**\n * Set the callback for the `video_receive_frame` event. Pass NULL to unset.\n *\n */\nvoid toxav_callback_video_receive_frame(ToxAV *toxAV, toxav_video_receive_frame_cb *callback, void *user_data);\n\n/**\n * NOTE Compatibility with old toxav group calls TODO remove\n */\n/* Create a new toxav group.\n *\n * return group number on success.\n * return -1 on failure.\n *\n * Audio data callback format:\n *   audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n */\nint toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t,\n                           unsigned int, void *), void *userdata);\n\n/* Join a AV group (you need to have been invited first.)\n *\n * returns group number on success\n * returns -1 on failure.\n *\n * Audio data callback format (same as the one for toxav_add_av_groupchat()):\n *   audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n */\nint toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length,\n                            void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata);\n\n/* Send audio to the group chat.\n *\n * return 0 on success.\n * return -1 on failure.\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n *\n * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000)\n * Valid number of channels are 1 or 2.\n * Valid sample rates are 8000, 12000, 16000, 24000, or 48000.\n *\n * Recommended values are: samples = 960, channels = 1, sample_rate = 48000\n */\nint toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,\n                           unsigned int sample_rate);\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* TOXAV_H */\n"
  },
  {
    "path": "toxav/toxav_old.c",
    "content": "/* toxav_old.h\n *\n * Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n * This file is part of Tox.\n *\n * Tox is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * Tox is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n/**\n * This file contains the group chats code for the backwards compatibility.\n */\n\n#include \"toxav.h\"\n#include \"group.h\"\n\n/* Create a new toxav group.\n *\n * return group number on success.\n * return -1 on failure.\n *\n * Audio data callback format:\n *   audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n */\nint toxav_add_av_groupchat(struct Tox *tox, void (*audio_callback)(void *, int, int, const int16_t *, unsigned int,\n                           uint8_t, unsigned int, void *), void *userdata)\n{\n    Messenger *m = (Messenger *)tox;\n    return add_av_groupchat(m->group_chat_object, audio_callback, userdata);\n}\n\n/* Join a AV group (you need to have been invited first.)\n *\n * returns group number on success\n * returns -1 on failure.\n *\n * Audio data callback format (same as the one for toxav_add_av_groupchat()):\n *   audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata)\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n */\nint toxav_join_av_groupchat(struct Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length,\n                            void (*audio_callback)(void *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),\n                            void *userdata)\n{\n    Messenger *m = (Messenger *)tox;\n    return join_av_groupchat(m->group_chat_object, friendnumber, data, length, audio_callback, userdata);\n}\n\n/* Send audio to the group chat.\n *\n * return 0 on success.\n * return -1 on failure.\n *\n * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).\n *\n * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000)\n * Valid number of channels are 1 or 2.\n * Valid sample rates are 8000, 12000, 16000, 24000, or 48000.\n *\n * Recommended values are: samples = 960, channels = 1, sample_rate = 48000\n */\nint toxav_group_send_audio(struct Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,\n                           unsigned int sample_rate)\n{\n    Messenger *m = (Messenger *)tox;\n    return group_send_audio(m->group_chat_object, groupnumber, pcm, samples, channels, sample_rate);\n}"
  },
  {
    "path": "toxav/video.c",
    "content": "/**  video.c\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"video.h\"\n#include \"msi.h\"\n#include \"rtp.h\"\n\n#include \"../toxcore/logger.h\"\n#include \"../toxcore/network.h\"\n\n#define MAX_DECODE_TIME_US 0 /* Good quality encode. */\n#define VIDEO_DECODE_BUFFER_SIZE 20\n\nVCSession *vc_new(ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data)\n{\n    VCSession *vc = calloc(sizeof(VCSession), 1);\n\n    if (!vc) {\n        LOGGER_WARNING(\"Allocation failed! Application might misbehave!\");\n        return NULL;\n    }\n\n    if (create_recursive_mutex(vc->queue_mutex) != 0) {\n        LOGGER_WARNING(\"Failed to create recursive mutex!\");\n        free(vc);\n        return NULL;\n    }\n\n    if (!(vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE)))\n        goto BASE_CLEANUP;\n\n    int rc = vpx_codec_dec_init(vc->decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0);\n\n    if (rc != VPX_CODEC_OK) {\n        LOGGER_ERROR(\"Init video_decoder failed: %s\", vpx_codec_err_to_string(rc));\n        goto BASE_CLEANUP;\n    }\n\n    /* Set encoder to some initial values\n     */\n    vpx_codec_enc_cfg_t  cfg;\n    rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);\n\n    if (rc != VPX_CODEC_OK) {\n        LOGGER_ERROR(\"Failed to get config: %s\", vpx_codec_err_to_string(rc));\n        goto BASE_CLEANUP_1;\n    }\n\n    cfg.rc_target_bitrate = 500000;\n    cfg.g_w = 800;\n    cfg.g_h = 600;\n    cfg.g_pass = VPX_RC_ONE_PASS;\n    /* FIXME If we set error resilience the app will crash due to bug in vp8.\n             Perhaps vp9 has solved it?*/\n//     cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;\n    cfg.g_lag_in_frames = 0;\n    cfg.kf_min_dist = 0;\n    cfg.kf_max_dist = 48;\n    cfg.kf_mode = VPX_KF_AUTO;\n\n    rc = vpx_codec_enc_init(vc->encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);\n\n    if (rc != VPX_CODEC_OK) {\n        LOGGER_ERROR(\"Failed to initialize encoder: %s\", vpx_codec_err_to_string(rc));\n        goto BASE_CLEANUP_1;\n    }\n\n    rc = vpx_codec_control(vc->encoder, VP8E_SET_CPUUSED, 8);\n\n    if (rc != VPX_CODEC_OK) {\n        LOGGER_ERROR(\"Failed to set encoder control setting: %s\", vpx_codec_err_to_string(rc));\n        vpx_codec_destroy(vc->encoder);\n        goto BASE_CLEANUP_1;\n    }\n\n    vc->linfts = current_time_monotonic();\n    vc->lcfd = 60;\n    vc->vcb.first = cb;\n    vc->vcb.second = cb_data;\n    vc->friend_number = friend_number;\n    vc->av = av;\n\n    return vc;\n\nBASE_CLEANUP_1:\n    vpx_codec_destroy(vc->decoder);\nBASE_CLEANUP:\n    pthread_mutex_destroy(vc->queue_mutex);\n    rb_kill(vc->vbuf_raw);\n    free(vc);\n    return NULL;\n}\nvoid vc_kill(VCSession *vc)\n{\n    if (!vc)\n        return;\n\n    vpx_codec_destroy(vc->encoder);\n    vpx_codec_destroy(vc->decoder);\n\n    void *p;\n\n    while (rb_read(vc->vbuf_raw, (void **)&p))\n        free(p);\n\n    rb_kill(vc->vbuf_raw);\n\n    pthread_mutex_destroy(vc->queue_mutex);\n\n    LOGGER_DEBUG(\"Terminated video handler: %p\", vc);\n    free(vc);\n}\nvoid vc_iterate(VCSession *vc)\n{\n    if (!vc)\n        return;\n\n    struct RTPMessage *p;\n    int rc;\n\n    pthread_mutex_lock(vc->queue_mutex);\n\n    if (rb_read(vc->vbuf_raw, (void **)&p)) {\n        pthread_mutex_unlock(vc->queue_mutex);\n\n        rc = vpx_codec_decode(vc->decoder, p->data, p->len, NULL, MAX_DECODE_TIME_US);\n        free(p);\n\n        if (rc != VPX_CODEC_OK)\n            LOGGER_ERROR(\"Error decoding video: %s\", vpx_codec_err_to_string(rc));\n        else {\n            vpx_codec_iter_t iter = NULL;\n            vpx_image_t *dest = vpx_codec_get_frame(vc->decoder, &iter);\n\n            /* Play decoded images */\n            for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {\n                if (vc->vcb.first)\n                    vc->vcb.first(vc->av, vc->friend_number, dest->d_w, dest->d_h,\n                                  (const uint8_t *)dest->planes[0], (const uint8_t *)dest->planes[1], (const uint8_t *)dest->planes[2],\n                                  dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second);\n\n                vpx_img_free(dest);\n            }\n        }\n\n        return;\n    }\n\n    pthread_mutex_unlock(vc->queue_mutex);\n}\nint vc_queue_message(void *vcp, struct RTPMessage *msg)\n{\n    /* This function does the reconstruction of video packets.\n     * See more info about video splitting in docs\n     */\n    if (!vcp || !msg)\n        return -1;\n\n    if (msg->header.pt == (rtp_TypeVideo + 2) % 128) {\n        LOGGER_WARNING(\"Got dummy!\");\n        free(msg);\n        return 0;\n    }\n\n    if (msg->header.pt != rtp_TypeVideo % 128) {\n        LOGGER_WARNING(\"Invalid payload type!\");\n        free(msg);\n        return -1;\n    }\n\n    VCSession *vc = vcp;\n\n    pthread_mutex_lock(vc->queue_mutex);\n    free(rb_write(vc->vbuf_raw, msg));\n    {\n        /* Calculate time took for peer to send us this frame */\n        uint32_t t_lcfd = current_time_monotonic() - vc->linfts;\n        vc->lcfd = t_lcfd > 100 ? vc->lcfd : t_lcfd;\n        vc->linfts = current_time_monotonic();\n    }\n    pthread_mutex_unlock(vc->queue_mutex);\n\n    return 0;\n}\nint vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uint16_t height)\n{\n    if (!vc)\n        return -1;\n\n    vpx_codec_enc_cfg_t cfg = *vc->encoder->config.enc;\n    int rc;\n\n    if (cfg.rc_target_bitrate == bit_rate && cfg.g_w == width && cfg.g_h == height)\n        return 0; /* Nothing changed */\n\n    if (cfg.g_w == width && cfg.g_h == height) {\n        /* Only bit rate changed */\n        cfg.rc_target_bitrate = bit_rate;\n\n        rc = vpx_codec_enc_config_set(vc->encoder, &cfg);\n\n        if (rc != VPX_CODEC_OK) {\n            LOGGER_ERROR(\"Failed to set encoder control setting: %s\", vpx_codec_err_to_string(rc));\n            return -1;\n        }\n    } else {\n        /* Resolution is changed, must reinitialize encoder since libvpx v1.4 doesn't support\n         * reconfiguring encoder to use resolutions greater than initially set.\n         */\n\n        LOGGER_DEBUG(\"Have to reinitialize vpx encoder on session %p\", vc);\n\n        cfg.rc_target_bitrate = bit_rate;\n        cfg.g_w = width;\n        cfg.g_h = height;\n\n        vpx_codec_ctx_t new_c;\n\n        rc = vpx_codec_enc_init(&new_c, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);\n\n        if (rc != VPX_CODEC_OK) {\n            LOGGER_ERROR(\"Failed to initialize encoder: %s\", vpx_codec_err_to_string(rc));\n            return -1;\n        }\n\n        rc = vpx_codec_control(&new_c, VP8E_SET_CPUUSED, 8);\n\n        if (rc != VPX_CODEC_OK) {\n            LOGGER_ERROR(\"Failed to set encoder control setting: %s\", vpx_codec_err_to_string(rc));\n            vpx_codec_destroy(&new_c);\n            return -1;\n        }\n\n        vpx_codec_destroy(vc->encoder);\n        memcpy(vc->encoder, &new_c, sizeof(new_c));\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "toxav/video.h",
    "content": "/**  video.h\n *\n *   Copyright (C) 2013-2015 Tox project All Rights Reserved.\n *\n *   This file is part of Tox.\n *\n *   Tox is free software: you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation, either version 3 of the License, or\n *   (at your option) any later version.\n *\n *   Tox is distributed in the hope that it will be useful,\n *   but WITHOUT ANY WARRANTY; without even the implied warranty of\n *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *   GNU General Public License for more details.\n *\n *   You should have received a copy of the GNU General Public License\n *   along with Tox. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef VIDEO_H\n#define VIDEO_H\n\n#include <vpx/vpx_decoder.h>\n#include <vpx/vpx_encoder.h>\n#include <vpx/vp8dx.h>\n#include <vpx/vp8cx.h>\n#include <vpx/vpx_image.h>\n#define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx())\n#define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx())\n\n#include <pthread.h>\n\n#include \"toxav.h\"\n\n#include \"../toxcore/util.h\"\n\nstruct RTPMessage;\n\ntypedef struct VCSession_s {\n    /* encoding */\n    vpx_codec_ctx_t encoder[1];\n    uint32_t frame_counter;\n\n    /* decoding */\n    vpx_codec_ctx_t decoder[1];\n    void *vbuf_raw; /* Un-decoded data */\n\n    uint64_t linfts; /* Last received frame time stamp */\n    uint32_t lcfd; /* Last calculated frame duration for incoming video payload */\n\n    ToxAV *av;\n    uint32_t friend_number;\n\n    PAIR(toxav_video_receive_frame_cb *, void *) vcb; /* Video frame receive callback */\n\n    pthread_mutex_t queue_mutex[1];\n} VCSession;\n\nVCSession *vc_new(ToxAV *av, uint32_t friend_number, toxav_video_receive_frame_cb *cb, void *cb_data);\nvoid vc_kill(VCSession *vc);\nvoid vc_iterate(VCSession *vc);\nint vc_queue_message(void *vcp, struct RTPMessage *msg);\nint vc_reconfigure_encoder(VCSession *vc, uint32_t bit_rate, uint16_t width, uint16_t height);\n\n#endif /* VIDEO_H */\n"
  },
  {
    "path": "toxcore/DHT.c",
    "content": "/* DHT.c\n *\n * An implementation of the DHT as seen in docs/updates/DHT.md\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n/*----------------------------------------------------------------------------------*/\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#ifdef DEBUG\n#include <assert.h>\n#endif\n\n#include \"logger.h\"\n\n#include \"DHT.h\"\n\n#ifdef ENABLE_ASSOC_DHT\n#include \"assoc.h\"\n#endif\n\n#include \"ping.h\"\n\n#include \"network.h\"\n#include \"LAN_discovery.h\"\n#include \"misc_tools.h\"\n#include \"util.h\"\n\n/* The timeout after which a node is discarded completely. */\n#define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL)\n\n/* Ping interval in seconds for each random sending of a get nodes request. */\n#define GET_NODE_INTERVAL 20\n\n#define MAX_PUNCHING_PORTS 48\n\n/* Interval in seconds between punching attempts*/\n#define PUNCH_INTERVAL 3\n\n#define MAX_NORMAL_PUNCHING_TRIES 5\n\n#define NAT_PING_REQUEST    0\n#define NAT_PING_RESPONSE   1\n\n/* Number of get node requests to send to quickly find close nodes. */\n#define MAX_BOOTSTRAP_TIMES 5\n\n/* Compares pk1 and pk2 with pk.\n *\n *  return 0 if both are same distance.\n *  return 1 if pk1 is closer.\n *  return 2 if pk2 is closer.\n */\nint id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2)\n{\n    size_t   i;\n    uint8_t distance1, distance2;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {\n\n        distance1 = pk[i] ^ pk1[i];\n        distance2 = pk[i] ^ pk2[i];\n\n        if (distance1 < distance2)\n            return 1;\n\n        if (distance1 > distance2)\n            return 2;\n    }\n\n    return 0;\n}\n\n/* Return index of first unequal bit number.\n */\nstatic unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2)\n{\n    unsigned int i, j = 0;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {\n        if (pk1[i] == pk2[i])\n            continue;\n\n        for (j = 0; j < 8; ++j) {\n            if ((pk1[i] & (1 << (7 - j))) != (pk2[i] & (1 << (7 - j))))\n                break;\n        }\n\n        break;\n    }\n\n    return i * 8 + j;\n}\n\n/* Shared key generations are costly, it is therefor smart to store commonly used\n * ones so that they can re used later without being computed again.\n *\n * If shared key is already in shared_keys, copy it to shared_key.\n * else generate it into shared_key and copy it to shared_keys\n */\nvoid get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, const uint8_t *secret_key, const uint8_t *public_key)\n{\n    uint32_t i, num = ~0, curr = 0;\n\n    for (i = 0; i < MAX_KEYS_PER_SLOT; ++i) {\n        int index = public_key[30] * MAX_KEYS_PER_SLOT + i;\n\n        if (shared_keys->keys[index].stored) {\n            if (public_key_cmp(public_key, shared_keys->keys[index].public_key) == 0) {\n                memcpy(shared_key, shared_keys->keys[index].shared_key, crypto_box_BEFORENMBYTES);\n                ++shared_keys->keys[index].times_requested;\n                shared_keys->keys[index].time_last_requested = unix_time();\n                return;\n            }\n\n            if (num != 0) {\n                if (is_timeout(shared_keys->keys[index].time_last_requested, KEYS_TIMEOUT)) {\n                    num = 0;\n                    curr = index;\n                } else if (num > shared_keys->keys[index].times_requested) {\n                    num = shared_keys->keys[index].times_requested;\n                    curr = index;\n                }\n            }\n        } else {\n            if (num != 0) {\n                num = 0;\n                curr = index;\n            }\n        }\n    }\n\n    encrypt_precompute(public_key, secret_key, shared_key);\n\n    if (num != (uint32_t)~0) {\n        shared_keys->keys[curr].stored = 1;\n        shared_keys->keys[curr].times_requested = 1;\n        memcpy(shared_keys->keys[curr].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n        memcpy(shared_keys->keys[curr].shared_key, shared_key, crypto_box_BEFORENMBYTES);\n        shared_keys->keys[curr].time_last_requested = unix_time();\n    }\n}\n\n/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key\n * for packets that we receive.\n */\nvoid DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key)\n{\n    get_shared_key(&dht->shared_keys_recv, shared_key, dht->self_secret_key, public_key);\n}\n\n/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key\n * for packets that we send.\n */\nvoid DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key)\n{\n    get_shared_key(&dht->shared_keys_sent, shared_key, dht->self_secret_key, public_key);\n}\n\nvoid to_net_family(IP *ip)\n{\n    if (ip->family == AF_INET)\n        ip->family = TOX_AF_INET;\n    else if (ip->family == AF_INET6)\n        ip->family = TOX_AF_INET6;\n}\n\nint to_host_family(IP *ip)\n{\n    if (ip->family == TOX_AF_INET) {\n        ip->family = AF_INET;\n        return 0;\n    } else if (ip->family == TOX_AF_INET6) {\n        ip->family = AF_INET6;\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n#define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES)\n#define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES)\n\n/* Return packet size of packed node with ip_family on success.\n * Return -1 on failure.\n */\nint packed_node_size(uint8_t ip_family)\n{\n    if (ip_family == AF_INET) {\n        return PACKED_NODE_SIZE_IP4;\n    } else if (ip_family == TCP_INET) {\n        return PACKED_NODE_SIZE_IP4;\n    } else if (ip_family == AF_INET6) {\n        return PACKED_NODE_SIZE_IP6;\n    } else if (ip_family == TCP_INET6) {\n        return PACKED_NODE_SIZE_IP6;\n    } else {\n        return -1;\n    }\n}\n\n\n/* Pack number of nodes into data of maxlength length.\n *\n * return length of packed nodes on success.\n * return -1 on failure.\n */\nint pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number)\n{\n    uint32_t i, packed_length = 0;\n\n    for (i = 0; i < number; ++i) {\n        int ipv6 = -1;\n        uint8_t net_family;\n\n        // FIXME use functions to convert endianness\n        if (nodes[i].ip_port.ip.family == AF_INET) {\n            ipv6 = 0;\n            net_family = TOX_AF_INET;\n        } else if (nodes[i].ip_port.ip.family == TCP_INET) {\n            ipv6 = 0;\n            net_family = TOX_TCP_INET;\n        } else if (nodes[i].ip_port.ip.family == AF_INET6) {\n            ipv6 = 1;\n            net_family = TOX_AF_INET6;\n        } else if (nodes[i].ip_port.ip.family == TCP_INET6) {\n            ipv6 = 1;\n            net_family = TOX_TCP_INET6;\n        } else {\n            return -1;\n        }\n\n        if (ipv6 == 0) {\n            uint32_t size = PACKED_NODE_SIZE_IP4;\n\n            if (packed_length + size > length)\n                return -1;\n\n            data[packed_length] = net_family;\n            memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip4, SIZE_IP4);\n            memcpy(data + packed_length + 1 + SIZE_IP4, &nodes[i].ip_port.port, sizeof(uint16_t));\n            memcpy(data + packed_length + 1 + SIZE_IP4 + sizeof(uint16_t), nodes[i].public_key, crypto_box_PUBLICKEYBYTES);\n            packed_length += size;\n        } else if (ipv6 == 1) {\n            uint32_t size = PACKED_NODE_SIZE_IP6;\n\n            if (packed_length + size > length)\n                return -1;\n\n            data[packed_length] = net_family;\n            memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip6, SIZE_IP6);\n            memcpy(data + packed_length + 1 + SIZE_IP6, &nodes[i].ip_port.port, sizeof(uint16_t));\n            memcpy(data + packed_length + 1 + SIZE_IP6 + sizeof(uint16_t), nodes[i].public_key, crypto_box_PUBLICKEYBYTES);\n            packed_length += size;\n        } else {\n            return -1;\n        }\n    }\n\n    return packed_length;\n}\n\n/* Unpack data of length into nodes of size max_num_nodes.\n * Put the length of the data processed in processed_data_len.\n * tcp_enabled sets if TCP nodes are expected (true) or not (false).\n *\n * return number of unpacked nodes on success.\n * return -1 on failure.\n */\nint unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,\n                 uint16_t length, uint8_t tcp_enabled)\n{\n    uint32_t num = 0, len_processed = 0;\n\n    while (num < max_num_nodes && len_processed < length) {\n        int ipv6 = -1;\n        uint8_t host_family;\n\n        if (data[len_processed] == TOX_AF_INET) {\n            ipv6 = 0;\n            host_family = AF_INET;\n        } else if (data[len_processed] == TOX_TCP_INET) {\n            if (!tcp_enabled)\n                return -1;\n\n            ipv6 = 0;\n            host_family = TCP_INET;\n        } else if (data[len_processed] == TOX_AF_INET6) {\n            ipv6 = 1;\n            host_family = AF_INET6;\n        } else if (data[len_processed] == TOX_TCP_INET6) {\n            if (!tcp_enabled)\n                return -1;\n\n            ipv6 = 1;\n            host_family = TCP_INET6;\n        } else {\n            return -1;\n        }\n\n        if (ipv6 == 0) {\n            uint32_t size = PACKED_NODE_SIZE_IP4;\n\n            if (len_processed + size > length)\n                return -1;\n\n            nodes[num].ip_port.ip.family = host_family;\n            memcpy(&nodes[num].ip_port.ip.ip4, data + len_processed + 1, SIZE_IP4);\n            memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + SIZE_IP4, sizeof(uint16_t));\n            memcpy(nodes[num].public_key, data + len_processed + 1 + SIZE_IP4 + sizeof(uint16_t), crypto_box_PUBLICKEYBYTES);\n            len_processed += size;\n            ++num;\n        } else if (ipv6 == 1) {\n            uint32_t size = PACKED_NODE_SIZE_IP6;\n\n            if (len_processed + size > length)\n                return -1;\n\n            nodes[num].ip_port.ip.family = host_family;\n            memcpy(&nodes[num].ip_port.ip.ip6, data + len_processed + 1, SIZE_IP6);\n            memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + SIZE_IP6, sizeof(uint16_t));\n            memcpy(nodes[num].public_key, data + len_processed + 1 + SIZE_IP6 + sizeof(uint16_t), crypto_box_PUBLICKEYBYTES);\n            len_processed += size;\n            ++num;\n        } else {\n            return -1;\n        }\n    }\n\n    if (processed_data_len)\n        *processed_data_len = len_processed;\n\n    return num;\n}\n\n\n\n/* Check if client with public_key is already in list of length length.\n * If it is then set its corresponding timestamp to current time.\n * If the id is already in the list with a different ip_port, update it.\n *  TODO: Maybe optimize this.\n *\n *  return True(1) or False(0)\n */\nstatic int client_or_ip_port_in_list(Client_data *list, uint16_t length, const uint8_t *public_key, IP_Port ip_port)\n{\n    uint32_t i;\n    uint64_t temp_time = unix_time();\n\n    /* if public_key is in list, find it and maybe overwrite ip_port */\n    for (i = 0; i < length; ++i)\n        if (id_equal(list[i].public_key, public_key)) {\n            /* Refresh the client timestamp. */\n            if (ip_port.ip.family == AF_INET) {\n\n                LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {\n                LOGGER_TRACE(\"coipil[%u]: switching ipv4 from %s:%u to %s:%u\", i,\n                             ip_ntoa(&list[i].assoc4.ip_port.ip), ntohs(list[i].assoc4.ip_port.port),\n                             ip_ntoa(&ip_port.ip), ntohs(ip_port.port));\n                }\n                            );\n\n                if (LAN_ip(list[i].assoc4.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)\n                    return 1;\n\n                list[i].assoc4.ip_port = ip_port;\n                list[i].assoc4.timestamp = temp_time;\n            } else if (ip_port.ip.family == AF_INET6) {\n\n                LOGGER_SCOPE( if (!ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {\n                LOGGER_TRACE(\"coipil[%u]: switching ipv6 from %s:%u to %s:%u\", i,\n                             ip_ntoa(&list[i].assoc6.ip_port.ip), ntohs(list[i].assoc6.ip_port.port),\n                             ip_ntoa(&ip_port.ip), ntohs(ip_port.port));\n                }\n                            );\n\n                if (LAN_ip(list[i].assoc6.ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0)\n                    return 1;\n\n                list[i].assoc6.ip_port = ip_port;\n                list[i].assoc6.timestamp = temp_time;\n            }\n\n            return 1;\n        }\n\n    /* public_key not in list yet: see if we can find an identical ip_port, in\n     * that case we kill the old public_key by overwriting it with the new one\n     * TODO: maybe we SHOULDN'T do that if that public_key is in a friend_list\n     * and the one who is the actual friend's public_key/address set? */\n    for (i = 0; i < length; ++i) {\n        /* MAYBE: check the other address, if valid, don't nuke? */\n        if ((ip_port.ip.family == AF_INET) && ipport_equal(&list[i].assoc4.ip_port, &ip_port)) {\n            /* Initialize client timestamp. */\n            list[i].assoc4.timestamp = temp_time;\n            memcpy(list[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n\n            LOGGER_DEBUG(\"coipil[%u]: switching public_key (ipv4)\", i);\n\n            /* kill the other address, if it was set */\n            memset(&list[i].assoc6, 0, sizeof(list[i].assoc6));\n            return 1;\n        } else if ((ip_port.ip.family == AF_INET6) && ipport_equal(&list[i].assoc6.ip_port, &ip_port)) {\n            /* Initialize client timestamp. */\n            list[i].assoc6.timestamp = temp_time;\n            memcpy(list[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n\n            LOGGER_DEBUG(\"coipil[%u]: switching public_key (ipv6)\", i);\n\n            /* kill the other address, if it was set */\n            memset(&list[i].assoc4, 0, sizeof(list[i].assoc4));\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\n/* Check if client with public_key is already in node format list of length length.\n *\n *  return 1 if true.\n *  return 0 if false.\n */\nstatic int client_in_nodelist(const Node_format *list, uint16_t length, const uint8_t *public_key)\n{\n    uint32_t i;\n\n    for (i = 0; i < length; ++i) {\n        if (id_equal(list[i].public_key, public_key))\n            return 1;\n    }\n\n    return 0;\n}\n\n/*  return friend number from the public_key.\n *  return -1 if a failure occurs.\n */\nstatic int friend_number(const DHT *dht, const uint8_t *public_key)\n{\n    uint32_t i;\n\n    for (i = 0; i < dht->num_friends; ++i) {\n        if (id_equal(dht->friends_list[i].public_key, public_key))\n            return i;\n    }\n\n    return -1;\n}\n\n/* Add node to the node list making sure only the nodes closest to cmp_pk are in the list.\n */\n_Bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port,\n                  const uint8_t *cmp_pk)\n{\n    uint8_t pk_bak[crypto_box_PUBLICKEYBYTES];\n    IP_Port ip_port_bak;\n\n    unsigned int i;\n\n    for (i = 0; i < length; ++i) {\n        if (id_closest(cmp_pk, nodes_list[i].public_key, pk) == 2) {\n            memcpy(pk_bak, nodes_list[i].public_key, crypto_box_PUBLICKEYBYTES);\n            ip_port_bak = nodes_list[i].ip_port;\n            memcpy(nodes_list[i].public_key, pk, crypto_box_PUBLICKEYBYTES);\n            nodes_list[i].ip_port = ip_port;\n\n            if (i != (length - 1))\n                add_to_list(nodes_list, length, pk_bak, ip_port_bak, cmp_pk);\n\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\n/*TODO: change this to 7 when done*/\n#define HARDENING_ALL_OK 2\n/* return 0 if not.\n * return 1 if route request are ok\n * return 2 if it responds to send node packets correctly\n * return 4 if it can test other nodes correctly\n * return HARDENING_ALL_OK if all ok.\n */\nstatic uint8_t hardening_correct(const Hardening *h)\n{\n    return h->routes_requests_ok + (h->send_nodes_ok << 1) + (h->testing_requests << 2);\n}\n/*\n * helper for get_close_nodes(). argument list is a monster :D\n */\nstatic void get_close_nodes_inner(const uint8_t *public_key, Node_format *nodes_list,\n                                  sa_family_t sa_family, const Client_data *client_list, uint32_t client_list_length,\n                                  uint32_t *num_nodes_ptr, uint8_t is_LAN, uint8_t want_good)\n{\n    if ((sa_family != AF_INET) && (sa_family != AF_INET6) && (sa_family != 0))\n        return;\n\n    uint32_t num_nodes = *num_nodes_ptr;\n    uint32_t i;\n\n    for (i = 0; i < client_list_length; i++) {\n        const Client_data *client = &client_list[i];\n\n        /* node already in list? */\n        if (client_in_nodelist(nodes_list, MAX_SENT_NODES, client->public_key))\n            continue;\n\n        const IPPTsPng *ipptp = NULL;\n\n        if (sa_family == AF_INET) {\n            ipptp = &client->assoc4;\n        } else if (sa_family == AF_INET6) {\n            ipptp = &client->assoc6;\n        } else {\n            if (client->assoc4.timestamp >= client->assoc6.timestamp) {\n                ipptp = &client->assoc4;\n            } else {\n                ipptp = &client->assoc6;\n            }\n        }\n\n        /* node not in a good condition? */\n        if (is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT))\n            continue;\n\n        /* don't send LAN ips to non LAN peers */\n        if (LAN_ip(ipptp->ip_port.ip) == 0 && !is_LAN)\n            continue;\n\n        if (LAN_ip(ipptp->ip_port.ip) != 0 && want_good && hardening_correct(&ipptp->hardening) != HARDENING_ALL_OK\n                && !id_equal(public_key, client->public_key))\n            continue;\n\n        if (num_nodes < MAX_SENT_NODES) {\n            memcpy(nodes_list[num_nodes].public_key,\n                   client->public_key,\n                   crypto_box_PUBLICKEYBYTES );\n\n            nodes_list[num_nodes].ip_port = ipptp->ip_port;\n            num_nodes++;\n        } else {\n            add_to_list(nodes_list, MAX_SENT_NODES, client->public_key, ipptp->ip_port, public_key);\n        }\n    }\n\n    *num_nodes_ptr = num_nodes;\n}\n\n/* Find MAX_SENT_NODES nodes closest to the public_key for the send nodes request:\n * put them in the nodes_list and return how many were found.\n *\n * TODO: For the love of based <your favorite deity, in doubt use \"love\"> make\n * this function cleaner and much more efficient.\n *\n * want_good : do we want only good nodes as checked with the hardening returned or not?\n */\nstatic int get_somewhat_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list,\n                                    sa_family_t sa_family, uint8_t is_LAN, uint8_t want_good)\n{\n    uint32_t num_nodes = 0, i;\n    get_close_nodes_inner(public_key, nodes_list, sa_family,\n                          dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, 0);\n\n    /*TODO uncomment this when hardening is added to close friend clients\n        for (i = 0; i < dht->num_friends; ++i)\n            get_close_nodes_inner(dht, public_key, nodes_list, sa_family,\n                                  dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,\n                                  &num_nodes, is_LAN, want_good);\n    */\n    for (i = 0; i < dht->num_friends; ++i)\n        get_close_nodes_inner(public_key, nodes_list, sa_family,\n                              dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,\n                              &num_nodes, is_LAN, 0);\n\n    return num_nodes;\n}\n\nint get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, sa_family_t sa_family,\n                    uint8_t is_LAN, uint8_t want_good)\n{\n    memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format));\n#ifdef ENABLE_ASSOC_DHT\n\n    if (!dht->assoc)\n#endif\n        return get_somewhat_close_nodes(dht, public_key, nodes_list, sa_family, is_LAN, want_good);\n\n#ifdef ENABLE_ASSOC_DHT\n    //TODO: assoc, sa_family 0 (don't care if ipv4 or ipv6) support.\n    Client_data *result[MAX_SENT_NODES];\n\n    Assoc_close_entries request;\n    memset(&request, 0, sizeof(request));\n    request.count = MAX_SENT_NODES;\n    request.count_good = MAX_SENT_NODES - 2; /* allow 2 'indirect' nodes */\n    request.result = result;\n    request.wanted_id = public_key;\n    request.flags = (is_LAN ? LANOk : 0) + (sa_family == AF_INET ? ProtoIPv4 : ProtoIPv6);\n\n    uint8_t num_found = Assoc_get_close_entries(dht->assoc, &request);\n\n    if (!num_found) {\n        LOGGER_DEBUG(\"get_close_nodes(): Assoc_get_close_entries() returned zero nodes\");\n        return get_somewhat_close_nodes(dht, public_key, nodes_list, sa_family, is_LAN, want_good);\n    }\n\n    LOGGER_DEBUG(\"get_close_nodes(): Assoc_get_close_entries() returned %i 'direct' and %i 'indirect' nodes\",\n                 request.count_good, num_found - request.count_good);\n\n    uint8_t i, num_returned = 0;\n\n    for (i = 0; i < num_found; i++) {\n        Client_data *client = result[i];\n\n        if (client) {\n            id_copy(nodes_list[num_returned].public_key, client->public_key);\n\n            if (sa_family == AF_INET)\n                if (ipport_isset(&client->assoc4.ip_port)) {\n                    nodes_list[num_returned].ip_port = client->assoc4.ip_port;\n                    num_returned++;\n                    continue;\n                }\n\n            if (sa_family == AF_INET6)\n                if (ipport_isset(&client->assoc6.ip_port)) {\n                    nodes_list[num_returned].ip_port = client->assoc6.ip_port;\n                    num_returned++;\n                    continue;\n                }\n        }\n    }\n\n    return num_returned;\n#endif\n}\n\nstatic uint8_t cmp_public_key[crypto_box_PUBLICKEYBYTES];\nstatic int cmp_dht_entry(const void *a, const void *b)\n{\n    Client_data entry1, entry2;\n    memcpy(&entry1, a, sizeof(Client_data));\n    memcpy(&entry2, b, sizeof(Client_data));\n    int t1 = is_timeout(entry1.assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(entry1.assoc6.timestamp, BAD_NODE_TIMEOUT);\n    int t2 = is_timeout(entry2.assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(entry2.assoc6.timestamp, BAD_NODE_TIMEOUT);\n\n    if (t1 && t2)\n        return 0;\n\n    if (t1)\n        return -1;\n\n    if (t2)\n        return 1;\n\n    t1 = hardening_correct(&entry1.assoc4.hardening) != HARDENING_ALL_OK\n         && hardening_correct(&entry1.assoc6.hardening) != HARDENING_ALL_OK;\n    t2 = hardening_correct(&entry2.assoc4.hardening) != HARDENING_ALL_OK\n         && hardening_correct(&entry2.assoc6.hardening) != HARDENING_ALL_OK;\n\n    if (t1 != t2) {\n        if (t1)\n            return -1;\n\n        if (t2)\n            return 1;\n    }\n\n    int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key);\n\n    if (close == 1)\n        return 1;\n\n    if (close == 2)\n        return -1;\n\n    return 0;\n}\n\n/* Is it ok to store node with public_key in client.\n *\n * return 0 if node can't be stored.\n * return 1 if it can.\n */\nstatic unsigned int store_node_ok(const Client_data *client, const uint8_t *public_key, const uint8_t *comp_public_key)\n{\n    if ((is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT))\n            || (id_closest(comp_public_key, client->public_key, public_key) == 2)) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\nstatic void sort_client_list(Client_data *list, unsigned int length, const uint8_t *comp_public_key)\n{\n    memcpy(cmp_public_key, comp_public_key, crypto_box_PUBLICKEYBYTES);\n    qsort(list, length, sizeof(Client_data), cmp_dht_entry);\n}\n\n/* Replace a first bad (or empty) node with this one\n *  or replace a possibly bad node (tests failed or not done yet)\n *  that is further than any other in the list\n *  from the comp_public_key\n *  or replace a good node that is further\n *  than any other in the list from the comp_public_key\n *  and further than public_key.\n *\n * Do not replace any node if the list has no bad or possibly bad nodes\n *  and all nodes in the list are closer to comp_public_key\n *  than public_key.\n *\n *  returns True(1) when the item was stored, False(0) otherwise */\nstatic int replace_all(   Client_data    *list,\n                          uint16_t        length,\n                          const uint8_t  *public_key,\n                          IP_Port         ip_port,\n                          const uint8_t  *comp_public_key )\n{\n    if ((ip_port.ip.family != AF_INET) && (ip_port.ip.family != AF_INET6))\n        return 0;\n\n    if (store_node_ok(&list[1], public_key, comp_public_key) || store_node_ok(&list[0], public_key, comp_public_key)) {\n        sort_client_list(list, length, comp_public_key);\n\n        IPPTsPng *ipptp_write = NULL;\n        IPPTsPng *ipptp_clear = NULL;\n\n        Client_data *client = &list[0];\n\n        if (ip_port.ip.family == AF_INET) {\n            ipptp_write = &client->assoc4;\n            ipptp_clear = &client->assoc6;\n        } else {\n            ipptp_write = &client->assoc6;\n            ipptp_clear = &client->assoc4;\n        }\n\n        id_copy(client->public_key, public_key);\n        ipptp_write->ip_port = ip_port;\n        ipptp_write->timestamp = unix_time();\n\n        ip_reset(&ipptp_write->ret_ip_port.ip);\n        ipptp_write->ret_ip_port.port = 0;\n        ipptp_write->ret_timestamp = 0;\n\n        /* zero out other address */\n        memset(ipptp_clear, 0, sizeof(*ipptp_clear));\n\n        return 1;\n    }\n\n    return 0;\n}\n\n/* Add node to close list.\n *\n * simulate is set to 1 if we want to check if a node can be added to the list without adding it.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int add_to_close(DHT *dht, const uint8_t *public_key, IP_Port ip_port, _Bool simulate)\n{\n    unsigned int i;\n\n    unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);\n\n    if (index > LCLIENT_LENGTH)\n        index = LCLIENT_LENGTH - 1;\n\n    for (i = 0; i < LCLIENT_NODES; ++i) {\n        Client_data *client = &dht->close_clientlist[(index * LCLIENT_NODES) + i];\n\n        if (is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) {\n            if (!simulate) {\n                IPPTsPng *ipptp_write = NULL;\n                IPPTsPng *ipptp_clear = NULL;\n\n                if (ip_port.ip.family == AF_INET) {\n                    ipptp_write = &client->assoc4;\n                    ipptp_clear = &client->assoc6;\n                } else {\n                    ipptp_write = &client->assoc6;\n                    ipptp_clear = &client->assoc4;\n                }\n\n                id_copy(client->public_key, public_key);\n                ipptp_write->ip_port = ip_port;\n                ipptp_write->timestamp = unix_time();\n\n                ip_reset(&ipptp_write->ret_ip_port.ip);\n                ipptp_write->ret_ip_port.port = 0;\n                ipptp_write->ret_timestamp = 0;\n\n                /* zero out other address */\n                memset(ipptp_clear, 0, sizeof(*ipptp_clear));\n            }\n\n            return 0;\n        }\n    }\n\n    return -1;\n}\n\n/* Return 1 if node can be added to close list, 0 if it can't.\n */\n_Bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port)\n{\n    if (add_to_close(dht, public_key, ip_port, 1) == 0) {\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic _Bool is_pk_in_client_list(Client_data *list, unsigned int client_list_length, const uint8_t *public_key,\n                                  IP_Port ip_port)\n{\n    unsigned int i;\n\n    for (i = 0; i < client_list_length; ++i) {\n        if ((ip_port.ip.family == AF_INET && !is_timeout(list[i].assoc4.timestamp, BAD_NODE_TIMEOUT))\n                || (ip_port.ip.family == AF_INET6 && !is_timeout(list[i].assoc6.timestamp, BAD_NODE_TIMEOUT))) {\n            if (public_key_cmp(list[i].public_key, public_key) == 0) {\n                return 1;\n            }\n        }\n    }\n\n    return 0;\n}\n\n/* Check if the node obtained with a get_nodes with public_key should be pinged.\n * NOTE: for best results call it after addto_lists;\n *\n * return 0 if the node should not be pinged.\n * return 1 if it should.\n */\nstatic unsigned int ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_Port ip_port)\n{\n    _Bool ret = 0;\n\n    if (add_to_close(dht, public_key, ip_port, 1) == 0) {\n        ret = 1;\n    }\n\n    if (ret && !client_in_nodelist(dht->to_bootstrap, dht->num_to_bootstrap, public_key)) {\n        if (dht->num_to_bootstrap < MAX_CLOSE_TO_BOOTSTRAP_NODES) {\n            memcpy(dht->to_bootstrap[dht->num_to_bootstrap].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n            dht->to_bootstrap[dht->num_to_bootstrap].ip_port = ip_port;\n            ++dht->num_to_bootstrap;\n        } else {\n            //TODO: ipv6 vs v4\n            add_to_list(dht->to_bootstrap, MAX_CLOSE_TO_BOOTSTRAP_NODES, public_key, ip_port, dht->self_public_key);\n        }\n    }\n\n    unsigned int i;\n\n    for (i = 0; i < dht->num_friends; ++i) {\n        _Bool store_ok = 0;\n\n        DHT_Friend *friend = &dht->friends_list[i];\n\n        if (store_node_ok(&friend->client_list[1], public_key, friend->public_key)) {\n            store_ok = 1;\n        }\n\n        if (store_node_ok(&friend->client_list[0], public_key, friend->public_key)) {\n            store_ok = 1;\n        }\n\n        if (store_ok && !client_in_nodelist(friend->to_bootstrap, friend->num_to_bootstrap, public_key)\n                && !is_pk_in_client_list(friend->client_list, MAX_FRIEND_CLIENTS, public_key, ip_port)) {\n            if (friend->num_to_bootstrap < MAX_SENT_NODES) {\n                memcpy(friend->to_bootstrap[friend->num_to_bootstrap].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n                friend->to_bootstrap[friend->num_to_bootstrap].ip_port = ip_port;\n                ++friend->num_to_bootstrap;\n            } else {\n                add_to_list(friend->to_bootstrap, MAX_SENT_NODES, public_key, ip_port, friend->public_key);\n            }\n\n            ret = 1;\n        }\n    }\n\n    return ret;\n}\n\n/* Attempt to add client with ip_port and public_key to the friends client list\n * and close_clientlist.\n *\n *  returns 1+ if the item is used in any list, 0 else\n */\nint addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key)\n{\n    uint32_t i, used = 0;\n\n    /* convert IPv4-in-IPv6 to IPv4 */\n    if ((ip_port.ip.family == AF_INET6) && IPV6_IPV4_IN_V6(ip_port.ip.ip6)) {\n        ip_port.ip.family = AF_INET;\n        ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3];\n    }\n\n    /* NOTE: Current behavior if there are two clients with the same id is\n     * to replace the first ip by the second.\n     */\n    if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, public_key, ip_port)) {\n        if (add_to_close(dht, public_key, ip_port, 0))\n            used++;\n    } else\n        used++;\n\n    DHT_Friend *friend_foundip = 0;\n\n    for (i = 0; i < dht->num_friends; ++i) {\n        if (!client_or_ip_port_in_list(dht->friends_list[i].client_list,\n                                       MAX_FRIEND_CLIENTS, public_key, ip_port)) {\n            if (replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,\n                            public_key, ip_port, dht->friends_list[i].public_key)) {\n\n                DHT_Friend *friend = &dht->friends_list[i];\n\n                if (public_key_cmp(public_key, friend->public_key) == 0) {\n                    friend_foundip = friend;\n                }\n\n                used++;\n            }\n        } else {\n            DHT_Friend *friend = &dht->friends_list[i];\n\n            if (public_key_cmp(public_key, friend->public_key) == 0) {\n                friend_foundip = friend;\n            }\n\n            used++;\n        }\n    }\n\n    if (friend_foundip) {\n        uint32_t j;\n\n        for (j = 0; j < friend_foundip->lock_count; ++j) {\n            if (friend_foundip->callbacks[j].ip_callback)\n                friend_foundip->callbacks[j].ip_callback(friend_foundip->callbacks[j].data, friend_foundip->callbacks[j].number,\n                        ip_port);\n        }\n    }\n\n#ifdef ENABLE_ASSOC_DHT\n\n    if (dht->assoc) {\n        IPPTs ippts;\n\n        ippts.ip_port = ip_port;\n        ippts.timestamp = unix_time();\n\n        Assoc_add_entry(dht->assoc, public_key, &ippts, NULL, used ? 1 : 0);\n    }\n\n#endif\n    return used;\n}\n\n/* If public_key is a friend or us, update ret_ip_port\n * nodepublic_key is the id of the node that sent us this info.\n */\nstatic int returnedip_ports(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *nodepublic_key)\n{\n    uint32_t i, j;\n    uint64_t temp_time = unix_time();\n\n    uint32_t used = 0;\n\n    /* convert IPv4-in-IPv6 to IPv4 */\n    if ((ip_port.ip.family == AF_INET6) && IPV6_IPV4_IN_V6(ip_port.ip.ip6)) {\n        ip_port.ip.family = AF_INET;\n        ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3];\n    }\n\n    if (id_equal(public_key, dht->self_public_key)) {\n        for (i = 0; i < LCLIENT_LIST; ++i) {\n            if (id_equal(nodepublic_key, dht->close_clientlist[i].public_key)) {\n                if (ip_port.ip.family == AF_INET) {\n                    dht->close_clientlist[i].assoc4.ret_ip_port = ip_port;\n                    dht->close_clientlist[i].assoc4.ret_timestamp = temp_time;\n                } else if (ip_port.ip.family == AF_INET6) {\n                    dht->close_clientlist[i].assoc6.ret_ip_port = ip_port;\n                    dht->close_clientlist[i].assoc6.ret_timestamp = temp_time;\n                }\n\n                ++used;\n                break;\n            }\n        }\n    } else {\n        for (i = 0; i < dht->num_friends; ++i) {\n            if (id_equal(public_key, dht->friends_list[i].public_key)) {\n                for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {\n                    if (id_equal(nodepublic_key, dht->friends_list[i].client_list[j].public_key)) {\n                        if (ip_port.ip.family == AF_INET) {\n                            dht->friends_list[i].client_list[j].assoc4.ret_ip_port = ip_port;\n                            dht->friends_list[i].client_list[j].assoc4.ret_timestamp = temp_time;\n                        } else if (ip_port.ip.family == AF_INET6) {\n                            dht->friends_list[i].client_list[j].assoc6.ret_ip_port = ip_port;\n                            dht->friends_list[i].client_list[j].assoc6.ret_timestamp = temp_time;\n                        }\n\n                        ++used;\n                        goto end;\n                    }\n                }\n            }\n        }\n    }\n\nend:\n#ifdef ENABLE_ASSOC_DHT\n\n    if (dht->assoc) {\n        IPPTs ippts;\n        ippts.ip_port = ip_port;\n        ippts.timestamp = temp_time;\n        /* this is only a hear-say entry, so ret-ipp is NULL, but used is required\n         * to decide how valuable it is (\"used\" may throw an \"unused\" entry out) */\n        Assoc_add_entry(dht->assoc, public_key, &ippts, NULL, used ? 1 : 0);\n    }\n\n#endif\n    return 0;\n}\n\n/* Send a getnodes request.\n   sendback_node is the node that it will send back the response to (set to NULL to disable this) */\nstatic int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id,\n                    const Node_format *sendback_node)\n{\n    /* Check if packet is going to be sent to ourself. */\n    if (id_equal(public_key, dht->self_public_key))\n        return -1;\n\n    uint8_t plain_message[sizeof(Node_format) * 2] = {0};\n\n    Node_format receiver;\n    memcpy(receiver.public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    receiver.ip_port = ip_port;\n    memcpy(plain_message, &receiver, sizeof(receiver));\n\n    uint64_t ping_id = 0;\n\n    if (sendback_node != NULL) {\n        memcpy(plain_message + sizeof(receiver), sendback_node, sizeof(Node_format));\n        ping_id = ping_array_add(&dht->dht_harden_ping_array, plain_message, sizeof(plain_message));\n    } else {\n        ping_id = ping_array_add(&dht->dht_ping_array, plain_message, sizeof(receiver));\n    }\n\n    if (ping_id == 0)\n        return -1;\n\n    uint8_t plain[crypto_box_PUBLICKEYBYTES + sizeof(ping_id)];\n    uint8_t encrypt[sizeof(plain) + crypto_box_MACBYTES];\n    uint8_t data[1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + sizeof(encrypt)];\n\n    memcpy(plain, client_id, crypto_box_PUBLICKEYBYTES);\n    memcpy(plain + crypto_box_PUBLICKEYBYTES, &ping_id, sizeof(ping_id));\n\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    DHT_get_shared_key_sent(dht, shared_key, public_key);\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    new_nonce(nonce);\n\n    int len = encrypt_data_symmetric( shared_key,\n                                      nonce,\n                                      plain,\n                                      sizeof(plain),\n                                      encrypt );\n\n    if (len != sizeof(encrypt))\n        return -1;\n\n    data[0] = NET_PACKET_GET_NODES;\n    memcpy(data + 1, dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);\n    memcpy(data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, encrypt, len);\n\n    return sendpacket(dht->net, ip_port, data, sizeof(data));\n}\n\n/* Send a send nodes response: message for IPv6 nodes */\nstatic int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id,\n                          const uint8_t *sendback_data, uint16_t length, const uint8_t *shared_encryption_key)\n{\n    /* Check if packet is going to be sent to ourself. */\n    if (id_equal(public_key, dht->self_public_key))\n        return -1;\n\n    if (length != sizeof(uint64_t))\n        return -1;\n\n    size_t Node_format_size = sizeof(Node_format);\n    uint8_t data[1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES\n                 + Node_format_size * MAX_SENT_NODES + length + crypto_box_MACBYTES];\n\n    Node_format nodes_list[MAX_SENT_NODES];\n    uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, 0, LAN_ip(ip_port.ip) == 0, 1);\n\n    uint8_t plain[1 + Node_format_size * MAX_SENT_NODES + length];\n    uint8_t encrypt[sizeof(plain) + crypto_box_MACBYTES];\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    new_nonce(nonce);\n\n    int nodes_length = 0;\n\n    if (num_nodes) {\n        nodes_length = pack_nodes(plain + 1, Node_format_size * MAX_SENT_NODES, nodes_list, num_nodes);\n\n        if (nodes_length <= 0)\n            return -1;\n    }\n\n    plain[0] = num_nodes;\n    memcpy(plain + 1 + nodes_length, sendback_data, length);\n    int len = encrypt_data_symmetric( shared_encryption_key,\n                                      nonce,\n                                      plain,\n                                      1 + nodes_length + length,\n                                      encrypt );\n\n    if (len != 1 + nodes_length + length + crypto_box_MACBYTES)\n        return -1;\n\n    data[0] = NET_PACKET_SEND_NODES_IPV6;\n    memcpy(data + 1, dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);\n    memcpy(data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, encrypt, len);\n\n    return sendpacket(dht->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + len);\n}\n\nstatic int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    if (length != (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + sizeof(\n                       uint64_t) + crypto_box_MACBYTES))\n        return 1;\n\n    DHT *dht = object;\n\n    /* Check if packet is from ourself. */\n    if (id_equal(packet + 1, dht->self_public_key))\n        return 1;\n\n    uint8_t plain[crypto_box_PUBLICKEYBYTES + sizeof(uint64_t)];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n\n    DHT_get_shared_key_recv(dht, shared_key, packet + 1);\n    int len = decrypt_data_symmetric( shared_key,\n                                      packet + 1 + crypto_box_PUBLICKEYBYTES,\n                                      packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,\n                                      crypto_box_PUBLICKEYBYTES + sizeof(uint64_t) + crypto_box_MACBYTES,\n                                      plain );\n\n    if (len != crypto_box_PUBLICKEYBYTES + sizeof(uint64_t))\n        return 1;\n\n    sendnodes_ipv6(dht, source, packet + 1, plain, plain + crypto_box_PUBLICKEYBYTES, sizeof(uint64_t), shared_key);\n\n    add_to_ping(dht->ping, packet + 1, source);\n\n    return 0;\n}\n/* return 0 if no\n   return 1 if yes */\nstatic uint8_t sent_getnode_to_node(DHT *dht, const uint8_t *public_key, IP_Port node_ip_port, uint64_t ping_id,\n                                    Node_format *sendback_node)\n{\n    uint8_t data[sizeof(Node_format) * 2];\n\n    if (ping_array_check(data, sizeof(data), &dht->dht_ping_array, ping_id) == sizeof(Node_format)) {\n        memset(sendback_node, 0, sizeof(Node_format));\n    } else if (ping_array_check(data, sizeof(data), &dht->dht_harden_ping_array, ping_id) == sizeof(data)) {\n        memcpy(sendback_node, data + sizeof(Node_format), sizeof(Node_format));\n    } else {\n        return 0;\n    }\n\n    Node_format test;\n    memcpy(&test, data, sizeof(Node_format));\n\n    if (!ipport_equal(&test.ip_port, &node_ip_port) || public_key_cmp(test.public_key, public_key) != 0)\n        return 0;\n\n    return 1;\n}\n\n/* Function is needed in following functions. */\nstatic int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id,\n                                      const uint8_t *nodes_data, uint16_t nodes_data_length);\n\nstatic int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint16_t length,\n                                 Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out)\n{\n    DHT *dht = object;\n    uint32_t cid_size = 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + 1 + sizeof(uint64_t) + crypto_box_MACBYTES;\n\n    if (length < cid_size) /* too short */\n        return 1;\n\n    uint32_t data_size = length - cid_size;\n\n    if (data_size == 0)\n        return 1;\n\n    if (data_size > sizeof(Node_format) * MAX_SENT_NODES) /* invalid length */\n        return 1;\n\n    uint8_t plain[1 + data_size + sizeof(uint64_t)];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    DHT_get_shared_key_sent(dht, shared_key, packet + 1);\n    int len = decrypt_data_symmetric(\n                  shared_key,\n                  packet + 1 + crypto_box_PUBLICKEYBYTES,\n                  packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,\n                  1 + data_size + sizeof(uint64_t) + crypto_box_MACBYTES,\n                  plain);\n\n    if ((unsigned int)len != sizeof(plain))\n        return 1;\n\n    if (plain[0] > size_plain_nodes)\n        return 1;\n\n    Node_format sendback_node;\n\n    uint64_t ping_id;\n    memcpy(&ping_id, plain + 1 + data_size, sizeof(ping_id));\n\n    if (!sent_getnode_to_node(dht, packet + 1, source, ping_id, &sendback_node))\n        return 1;\n\n    uint16_t length_nodes = 0;\n    int num_nodes = unpack_nodes(plain_nodes, plain[0], &length_nodes, plain + 1, data_size, 0);\n\n    if (length_nodes != data_size)\n        return 1;\n\n    if (num_nodes != plain[0])\n        return 1;\n\n    if (num_nodes < 0)\n        return 1;\n\n    /* store the address the *request* was sent to */\n    addto_lists(dht, source, packet + 1);\n\n    *num_nodes_out = num_nodes;\n\n    send_hardening_getnode_res(dht, &sendback_node, packet + 1, plain + 1, data_size);\n    return 0;\n}\n\nstatic int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    DHT *dht = object;\n    Node_format plain_nodes[MAX_SENT_NODES];\n    uint32_t num_nodes;\n\n    if (handle_sendnodes_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes))\n        return 1;\n\n    if (num_nodes == 0)\n        return 0;\n\n    uint32_t i;\n\n    for (i = 0; i < num_nodes; i++) {\n\n        if (ipport_isset(&plain_nodes[i].ip_port)) {\n            ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key, plain_nodes[i].ip_port);\n            returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1);\n        }\n    }\n\n    return 0;\n}\n\n/*----------------------------------------------------------------------------------*/\n/*------------------------END of packet handling functions--------------------------*/\n\nint DHT_addfriend(DHT *dht, const uint8_t *public_key, void (*ip_callback)(void *data, int32_t number, IP_Port),\n                  void *data, int32_t number, uint16_t *lock_count)\n{\n    int friend_num = friend_number(dht, public_key);\n\n    uint16_t lock_num;\n\n    if (friend_num != -1) { /* Is friend already in DHT? */\n        DHT_Friend *friend = &dht->friends_list[friend_num];\n\n        if (friend->lock_count == DHT_FRIEND_MAX_LOCKS)\n            return -1;\n\n        lock_num = friend->lock_count;\n        ++friend->lock_count;\n        friend->callbacks[lock_num].ip_callback = ip_callback;\n        friend->callbacks[lock_num].data = data;\n        friend->callbacks[lock_num].number = number;\n\n        if (lock_count)\n            *lock_count = lock_num + 1;\n\n        return 0;\n    }\n\n    DHT_Friend *temp;\n    temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1));\n\n    if (temp == NULL)\n        return -1;\n\n    dht->friends_list = temp;\n    DHT_Friend *friend = &dht->friends_list[dht->num_friends];\n    memset(friend, 0, sizeof(DHT_Friend));\n    memcpy(friend->public_key, public_key, crypto_box_PUBLICKEYBYTES);\n\n    friend->nat.NATping_id = random_64b();\n    ++dht->num_friends;\n\n    lock_num = friend->lock_count;\n    ++friend->lock_count;\n    friend->callbacks[lock_num].ip_callback = ip_callback;\n    friend->callbacks[lock_num].data = data;\n    friend->callbacks[lock_num].number = number;\n\n    if (lock_count)\n        *lock_count = lock_num + 1;\n\n    friend->num_to_bootstrap = get_close_nodes(dht, friend->public_key, friend->to_bootstrap, 0, 1, 0);\n\n    return 0;\n}\n\nint DHT_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count)\n{\n    int friend_num = friend_number(dht, public_key);\n\n    if (friend_num == -1) {\n        return -1;\n    }\n\n    DHT_Friend *friend = &dht->friends_list[friend_num];\n    --friend->lock_count;\n\n    if (friend->lock_count && lock_count) { /* DHT friend is still in use.*/\n        --lock_count;\n        friend->callbacks[lock_count].ip_callback = NULL;\n        friend->callbacks[lock_count].data = NULL;\n        friend->callbacks[lock_count].number = 0;\n        return 0;\n    }\n\n    DHT_Friend *temp;\n\n    --dht->num_friends;\n\n    if (dht->num_friends != friend_num) {\n        memcpy( &dht->friends_list[friend_num],\n                &dht->friends_list[dht->num_friends],\n                sizeof(DHT_Friend) );\n    }\n\n    if (dht->num_friends == 0) {\n        free(dht->friends_list);\n        dht->friends_list = NULL;\n        return 0;\n    }\n\n    temp = realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends));\n\n    if (temp == NULL)\n        return -1;\n\n    dht->friends_list = temp;\n    return 0;\n}\n\n/* TODO: Optimize this. */\nint DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port)\n{\n    uint32_t i, j;\n\n    ip_reset(&ip_port->ip);\n    ip_port->port = 0;\n\n    for (i = 0; i < dht->num_friends; ++i) {\n        /* Equal */\n        if (id_equal(dht->friends_list[i].public_key, public_key)) {\n            for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {\n                Client_data *client = &dht->friends_list[i].client_list[j];\n\n                if (id_equal(client->public_key, public_key)) {\n                    IPPTsPng *assoc = NULL;\n                    uint32_t a;\n\n                    for (a = 0, assoc = &client->assoc6; a < 2; a++, assoc = &client->assoc4)\n                        if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) {\n                            *ip_port = assoc->ip_port;\n                            return 1;\n                        }\n                }\n            }\n\n            return 0;\n        }\n    }\n\n    return -1;\n}\n\n/* returns number of nodes not in kill-timeout */\nstatic uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, const uint8_t *public_key,\n        Client_data *list, uint32_t list_count, uint32_t *bootstrap_times, _Bool sortable)\n{\n    uint32_t i;\n    uint8_t not_kill = 0;\n    uint64_t temp_time = unix_time();\n\n    uint32_t num_nodes = 0;\n    Client_data *client_list[list_count * 2];\n    IPPTsPng    *assoc_list[list_count * 2];\n    unsigned int sort = 0;\n    _Bool sort_ok = 0;\n\n    for (i = 0; i < list_count; i++) {\n        /* If node is not dead. */\n        Client_data *client = &list[i];\n        IPPTsPng *assoc;\n        uint32_t a;\n\n        for (a = 0, assoc = &client->assoc6; a < 2; a++, assoc = &client->assoc4)\n            if (!is_timeout(assoc->timestamp, KILL_NODE_TIMEOUT)) {\n                sort = 0;\n                not_kill++;\n\n                if (is_timeout(assoc->last_pinged, PING_INTERVAL)) {\n                    getnodes(dht, assoc->ip_port, client->public_key, public_key, NULL);\n                    assoc->last_pinged = temp_time;\n                }\n\n                /* If node is good. */\n                if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) {\n                    client_list[num_nodes] = client;\n                    assoc_list[num_nodes] = assoc;\n                    ++num_nodes;\n                }\n            } else {\n                ++sort;\n\n                /* Timed out should be at beginning, if they are not, sort the list. */\n                if (sort > 1 && sort < (((i + 1) * 2) - 1)) {\n                    sort_ok = 1;\n                }\n            }\n    }\n\n    if (sortable && sort_ok) {\n        sort_client_list(list, list_count, public_key);\n    }\n\n    if ((num_nodes != 0) && (is_timeout(*lastgetnode, GET_NODE_INTERVAL) || *bootstrap_times < MAX_BOOTSTRAP_TIMES)) {\n        uint32_t rand_node = rand() % (num_nodes);\n\n        if ((num_nodes - 1) != rand_node) {\n            rand_node += rand() % (num_nodes - (rand_node + 1));\n        }\n\n        getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key, NULL);\n\n        *lastgetnode = temp_time;\n        ++*bootstrap_times;\n    }\n\n    return not_kill;\n}\n\n/* Ping each client in the \"friends\" list every PING_INTERVAL seconds. Send a get nodes request\n * every GET_NODE_INTERVAL seconds to a random good node for each \"friend\" in our \"friends\" list.\n */\nstatic void do_DHT_friends(DHT *dht)\n{\n    unsigned int i, j;\n\n    for (i = 0; i < dht->num_friends; ++i) {\n        DHT_Friend *friend = &dht->friends_list[i];\n\n        for (j = 0; j < friend->num_to_bootstrap; ++j) {\n            getnodes(dht, friend->to_bootstrap[j].ip_port, friend->to_bootstrap[j].public_key, friend->public_key, NULL);\n        }\n\n        friend->num_to_bootstrap = 0;\n\n        do_ping_and_sendnode_requests(dht, &friend->lastgetnode, friend->public_key, friend->client_list, MAX_FRIEND_CLIENTS,\n                                      &friend->bootstrap_times, 1);\n    }\n}\n\n/* Ping each client in the close nodes list every PING_INTERVAL seconds.\n * Send a get nodes request every GET_NODE_INTERVAL seconds to a random good node in the list.\n */\nstatic void do_Close(DHT *dht)\n{\n    unsigned int i;\n\n    for (i = 0; i < dht->num_to_bootstrap; ++i) {\n        getnodes(dht, dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key, NULL);\n    }\n\n    dht->num_to_bootstrap = 0;\n\n    uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->self_public_key,\n                         dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times, 0);\n\n    if (!not_killed) {\n        /* all existing nodes are at least KILL_NODE_TIMEOUT,\n         * which means we are mute, as we only send packets to\n         * nodes NOT in KILL_NODE_TIMEOUT\n         *\n         * so: reset all nodes to be BAD_NODE_TIMEOUT, but not\n         * KILL_NODE_TIMEOUT, so we at least keep trying pings */\n        uint64_t badonly = unix_time() - BAD_NODE_TIMEOUT;\n        size_t i, a;\n\n        for (i = 0; i < LCLIENT_LIST; i++) {\n            Client_data *client = &dht->close_clientlist[i];\n            IPPTsPng *assoc;\n\n            for (a = 0, assoc = &client->assoc4; a < 2; a++, assoc = &client->assoc6)\n                if (assoc->timestamp)\n                    assoc->timestamp = badonly;\n        }\n    }\n}\n\nvoid DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id)\n{\n    getnodes(dht, *from_ipp, from_id, which_id, NULL);\n}\n\nvoid DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key)\n{\n    /*#ifdef ENABLE_ASSOC_DHT\n       if (dht->assoc) {\n           IPPTs ippts;\n           ippts.ip_port = ip_port;\n           ippts.timestamp = 0;\n\n           Assoc_add_entry(dht->assoc, public_key, &ippts, NULL, 0);\n       }\n       #endif*/\n\n    getnodes(dht, ip_port, public_key, dht->self_public_key, NULL);\n}\nint DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,\n                               uint16_t port, const uint8_t *public_key)\n{\n    IP_Port ip_port_v64;\n    IP *ip_extra = NULL;\n    IP_Port ip_port_v4;\n    ip_init(&ip_port_v64.ip, ipv6enabled);\n\n    if (ipv6enabled) {\n        /* setup for getting BOTH: an IPv6 AND an IPv4 address */\n        ip_port_v64.ip.family = AF_UNSPEC;\n        ip_reset(&ip_port_v4.ip);\n        ip_extra = &ip_port_v4.ip;\n    }\n\n    if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) {\n        ip_port_v64.port = port;\n        DHT_bootstrap(dht, ip_port_v64, public_key);\n\n        if ((ip_extra != NULL) && ip_isset(ip_extra)) {\n            ip_port_v4.port = port;\n            DHT_bootstrap(dht, ip_port_v4, public_key);\n        }\n\n        return 1;\n    } else\n        return 0;\n}\n\n/* Send the given packet to node with public_key\n *\n *  return -1 if failure.\n */\nint route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length)\n{\n    uint32_t i;\n\n    for (i = 0; i < LCLIENT_LIST; ++i) {\n        if (id_equal(public_key, dht->close_clientlist[i].public_key)) {\n            const Client_data *client = &dht->close_clientlist[i];\n\n            if (ip_isset(&client->assoc6.ip_port.ip))\n                return sendpacket(dht->net, client->assoc6.ip_port, packet, length);\n            else if (ip_isset(&client->assoc4.ip_port.ip))\n                return sendpacket(dht->net, client->assoc4.ip_port, packet, length);\n            else\n                break;\n        }\n    }\n\n    return -1;\n}\n\n/* Puts all the different ips returned by the nodes for a friend_num into array ip_portlist.\n * ip_portlist must be at least MAX_FRIEND_CLIENTS big.\n *\n *  return the number of ips returned.\n *  return 0 if we are connected to friend or if no ips were found.\n *  return -1 if no such friend.\n */\nstatic int friend_iplist(const DHT *dht, IP_Port *ip_portlist, uint16_t friend_num)\n{\n    if (friend_num >= dht->num_friends)\n        return -1;\n\n    DHT_Friend *friend = &dht->friends_list[friend_num];\n    Client_data *client;\n    IP_Port ipv4s[MAX_FRIEND_CLIENTS];\n    int num_ipv4s = 0;\n    IP_Port ipv6s[MAX_FRIEND_CLIENTS];\n    int num_ipv6s = 0;\n    int i;\n\n    for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {\n        client = &(friend->client_list[i]);\n\n        /* If ip is not zero and node is good. */\n        if (ip_isset(&client->assoc4.ret_ip_port.ip) && !is_timeout(client->assoc4.ret_timestamp, BAD_NODE_TIMEOUT)) {\n            ipv4s[num_ipv4s] = client->assoc4.ret_ip_port;\n            ++num_ipv4s;\n        }\n\n        if (ip_isset(&client->assoc6.ret_ip_port.ip) && !is_timeout(client->assoc6.ret_timestamp, BAD_NODE_TIMEOUT)) {\n            ipv6s[num_ipv6s] = client->assoc6.ret_ip_port;\n            ++num_ipv6s;\n        }\n\n        if (id_equal(client->public_key, friend->public_key))\n            if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) || !is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT))\n                return 0; /* direct connectivity */\n    }\n\n#ifdef FRIEND_IPLIST_PAD\n    memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port));\n\n    if (num_ipv6s == MAX_FRIEND_CLIENTS)\n        return MAX_FRIEND_CLIENTS;\n\n    int num_ipv4s_used = MAX_FRIEND_CLIENTS - num_ipv6s;\n\n    if (num_ipv4s_used > num_ipv4s)\n        num_ipv4s_used = num_ipv4s;\n\n    memcpy(&ip_portlist[num_ipv6s], ipv4s, num_ipv4s_used * sizeof(IP_Port));\n    return num_ipv6s + num_ipv4s_used;\n\n#else /* !FRIEND_IPLIST_PAD */\n\n    /* there must be some secret reason why we can't pad the longer list\n     * with the shorter one...\n     */\n    if (num_ipv6s >= num_ipv4s) {\n        memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port));\n        return num_ipv6s;\n    }\n\n    memcpy(ip_portlist, ipv4s, num_ipv4s * sizeof(IP_Port));\n    return num_ipv4s;\n\n#endif /* !FRIEND_IPLIST_PAD */\n}\n\n\n/* Send the following packet to everyone who tells us they are connected to friend_id.\n *\n *  return ip for friend.\n *  return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).\n */\nint route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length)\n{\n    int num = friend_number(dht, friend_id);\n\n    if (num == -1)\n        return 0;\n\n    uint32_t i, sent = 0;\n    uint8_t friend_sent[MAX_FRIEND_CLIENTS] = {0};\n\n    IP_Port ip_list[MAX_FRIEND_CLIENTS];\n    int ip_num = friend_iplist(dht, ip_list, num);\n\n    if (ip_num < (MAX_FRIEND_CLIENTS / 4))\n        return 0; /* Reason for that? */\n\n    DHT_Friend *friend = &dht->friends_list[num];\n    Client_data *client;\n\n    /* extra legwork, because having the outside allocating the space for us\n     * is *usually* good(tm) (bites us in the behind in this case though) */\n    uint32_t a;\n\n    for (a = 0; a < 2; a++)\n        for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {\n            if (friend_sent[i])/* Send one packet per client.*/\n                continue;\n\n            client = &friend->client_list[i];\n            IPPTsPng *assoc = NULL;\n\n            if (!a)\n                assoc = &client->assoc4;\n            else\n                assoc = &client->assoc6;\n\n            /* If ip is not zero and node is good. */\n            if (ip_isset(&assoc->ret_ip_port.ip) &&\n                    !is_timeout(assoc->ret_timestamp, BAD_NODE_TIMEOUT)) {\n                int retval = sendpacket(dht->net, assoc->ip_port, packet, length);\n\n                if ((unsigned int)retval == length) {\n                    ++sent;\n                    friend_sent[i] = 1;\n                }\n            }\n        }\n\n    return sent;\n}\n\n/* Send the following packet to one random person who tells us they are connected to friend_id.\n *\n *  return number of nodes the packet was sent to.\n */\nstatic int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length)\n{\n    int num = friend_number(dht, friend_id);\n\n    if (num == -1)\n        return 0;\n\n    DHT_Friend *friend = &dht->friends_list[num];\n    Client_data *client;\n\n    IP_Port ip_list[MAX_FRIEND_CLIENTS * 2];\n    int n = 0;\n    uint32_t i;\n\n    /* extra legwork, because having the outside allocating the space for us\n     * is *usually* good(tm) (bites us in the behind in this case though) */\n    uint32_t a;\n\n    for (a = 0; a < 2; a++)\n        for (i = 0; i < MAX_FRIEND_CLIENTS; ++i) {\n            client = &friend->client_list[i];\n            IPPTsPng *assoc = NULL;\n\n            if (!a)\n                assoc = &client->assoc4;\n            else\n                assoc = &client->assoc6;\n\n            /* If ip is not zero and node is good. */\n            if (ip_isset(&assoc->ret_ip_port.ip) && !is_timeout(assoc->ret_timestamp, BAD_NODE_TIMEOUT)) {\n                ip_list[n] = assoc->ip_port;\n                ++n;\n            }\n        }\n\n    if (n < 1)\n        return 0;\n\n    int retval = sendpacket(dht->net, ip_list[rand() % n], packet, length);\n\n    if ((unsigned int)retval == length)\n        return 1;\n\n    return 0;\n}\n\n/*----------------------------------------------------------------------------------*/\n/*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/\n\nstatic int send_NATping(DHT *dht, const uint8_t *public_key, uint64_t ping_id, uint8_t type)\n{\n    uint8_t data[sizeof(uint64_t) + 1];\n    uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];\n\n    int num = 0;\n\n    data[0] = type;\n    memcpy(data + 1, &ping_id, sizeof(uint64_t));\n    /* 254 is NAT ping request packet id */\n    int len = create_request(dht->self_public_key, dht->self_secret_key, packet, public_key, data,\n                             sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING);\n\n    if (len == -1)\n        return -1;\n\n    if (type == 0) /* If packet is request use many people to route it. */\n        num = route_tofriend(dht, public_key, packet, len);\n    else if (type == 1) /* If packet is response use only one person to route it */\n        num = routeone_tofriend(dht, public_key, packet, len);\n\n    if (num == 0)\n        return -1;\n\n    return num;\n}\n\n/* Handle a received ping request for. */\nstatic int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet,\n                          uint16_t length)\n{\n    if (length != sizeof(uint64_t) + 1)\n        return 1;\n\n    DHT *dht = object;\n    uint64_t ping_id;\n    memcpy(&ping_id, packet + 1, sizeof(uint64_t));\n\n    int friendnumber = friend_number(dht, source_pubkey);\n\n    if (friendnumber == -1)\n        return 1;\n\n    DHT_Friend *friend = &dht->friends_list[friendnumber];\n\n    if (packet[0] == NAT_PING_REQUEST) {\n        /* 1 is reply */\n        send_NATping(dht, source_pubkey, ping_id, NAT_PING_RESPONSE);\n        friend->nat.recvNATping_timestamp = unix_time();\n        return 0;\n    } else if (packet[0] == NAT_PING_RESPONSE) {\n        if (friend->nat.NATping_id == ping_id) {\n            friend->nat.NATping_id = random_64b();\n            friend->nat.hole_punching = 1;\n            return 0;\n        }\n    }\n\n    return 1;\n}\n\n/* Get the most common ip in the ip_portlist.\n * Only return ip if it appears in list min_num or more.\n * len must not be bigger than MAX_FRIEND_CLIENTS.\n *\n *  return ip of 0 if failure.\n */\nstatic IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)\n{\n    IP zero;\n    ip_reset(&zero);\n\n    if (len > MAX_FRIEND_CLIENTS)\n        return zero;\n\n    uint32_t i, j;\n    uint16_t numbers[MAX_FRIEND_CLIENTS] = {0};\n\n    for (i = 0; i < len; ++i) {\n        for (j = 0; j < len; ++j) {\n            if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip))\n                ++numbers[i];\n        }\n\n        if (numbers[i] >= min_num)\n            return ip_portlist[i].ip;\n    }\n\n    return zero;\n}\n\n/* Return all the ports for one ip in a list.\n * portlist must be at least len long,\n * where len is the length of ip_portlist.\n *\n *  return number of ports and puts the list of ports in portlist.\n */\nstatic uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t len, IP ip)\n{\n    uint32_t i;\n    uint16_t num = 0;\n\n    for (i = 0; i < len; ++i) {\n        if (ip_equal(&ip_portlist[i].ip, &ip)) {\n            portlist[num] = ntohs(ip_portlist[i].port);\n            ++num;\n        }\n    }\n\n    return num;\n}\n\nstatic void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports, uint16_t friend_num)\n{\n    if (numports > MAX_FRIEND_CLIENTS || numports == 0)\n        return;\n\n    uint32_t i;\n    uint32_t top = dht->friends_list[friend_num].nat.punching_index + MAX_PUNCHING_PORTS;\n    uint16_t firstport = port_list[0];\n\n    for (i = 0; i < numports; ++i) {\n        if (firstport != port_list[i])\n            break;\n    }\n\n    if (i == numports) { /* If all ports are the same, only try that one port. */\n        IP_Port pinging;\n        ip_copy(&pinging.ip, &ip);\n        pinging.port = htons(firstport);\n        send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key);\n    } else {\n        for (i = dht->friends_list[friend_num].nat.punching_index; i != top; ++i) {\n            /* TODO: Improve port guessing algorithm. */\n            uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1);\n            IP_Port pinging;\n            ip_copy(&pinging.ip, &ip);\n            pinging.port = htons(port);\n            send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key);\n        }\n\n        dht->friends_list[friend_num].nat.punching_index = i;\n    }\n\n    if (dht->friends_list[friend_num].nat.tries > MAX_NORMAL_PUNCHING_TRIES) {\n        top = dht->friends_list[friend_num].nat.punching_index2 + MAX_PUNCHING_PORTS;\n        uint16_t port = 1024;\n        IP_Port pinging;\n        ip_copy(&pinging.ip, &ip);\n\n        for (i = dht->friends_list[friend_num].nat.punching_index2; i != top; ++i) {\n            pinging.port = htons(port + i);\n            send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key);\n        }\n\n        dht->friends_list[friend_num].nat.punching_index2 = i - (MAX_PUNCHING_PORTS / 2);\n    }\n\n    ++dht->friends_list[friend_num].nat.tries;\n}\n\nstatic void do_NAT(DHT *dht)\n{\n    uint32_t i;\n    uint64_t temp_time = unix_time();\n\n    for (i = 0; i < dht->num_friends; ++i) {\n        IP_Port ip_list[MAX_FRIEND_CLIENTS];\n        int num = friend_iplist(dht, ip_list, i);\n\n        /* If already connected or friend is not online don't try to hole punch. */\n        if (num < MAX_FRIEND_CLIENTS / 2)\n            continue;\n\n        if (dht->friends_list[i].nat.NATping_timestamp + PUNCH_INTERVAL < temp_time) {\n            send_NATping(dht, dht->friends_list[i].public_key, dht->friends_list[i].nat.NATping_id, NAT_PING_REQUEST);\n            dht->friends_list[i].nat.NATping_timestamp = temp_time;\n        }\n\n        if (dht->friends_list[i].nat.hole_punching == 1 &&\n                dht->friends_list[i].nat.punching_timestamp + PUNCH_INTERVAL < temp_time &&\n                dht->friends_list[i].nat.recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) {\n\n            IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2);\n\n            if (!ip_isset(&ip))\n                continue;\n\n            uint16_t port_list[MAX_FRIEND_CLIENTS];\n            uint16_t numports = NAT_getports(port_list, ip_list, num, ip);\n            punch_holes(dht, ip, port_list, numports, i);\n\n            dht->friends_list[i].nat.punching_timestamp = temp_time;\n            dht->friends_list[i].nat.hole_punching = 0;\n        }\n    }\n}\n\n/*----------------------------------------------------------------------------------*/\n/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/\n\n#define HARDREQ_DATA_SIZE 384 /* Attempt to prevent amplification/other attacks*/\n\n#define CHECK_TYPE_ROUTE_REQ 0\n#define CHECK_TYPE_ROUTE_RES 1\n#define CHECK_TYPE_GETNODE_REQ 2\n#define CHECK_TYPE_GETNODE_RES 3\n#define CHECK_TYPE_TEST_REQ 4\n#define CHECK_TYPE_TEST_RES 5\n\nstatic int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8_t *contents, uint16_t length)\n{\n    if (length > HARDREQ_DATA_SIZE - 1)\n        return -1;\n\n    uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];\n    uint8_t data[HARDREQ_DATA_SIZE] = {0};\n    data[0] = type;\n    memcpy(data + 1, contents, length);\n    int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data,\n                             sizeof(data), CRYPTO_PACKET_HARDENING);\n\n    if (len == -1)\n        return -1;\n\n    return sendpacket(dht->net, sendto->ip_port, packet, len);\n}\n\n/* Send a get node hardening request */\nstatic int send_hardening_getnode_req(DHT *dht, Node_format *dest, Node_format *node_totest, uint8_t *search_id)\n{\n    uint8_t data[sizeof(Node_format) + crypto_box_PUBLICKEYBYTES];\n    memcpy(data, node_totest, sizeof(Node_format));\n    memcpy(data + sizeof(Node_format), search_id, crypto_box_PUBLICKEYBYTES);\n    return send_hardening_req(dht, dest, CHECK_TYPE_GETNODE_REQ, data, sizeof(Node_format) + crypto_box_PUBLICKEYBYTES);\n}\n\n/* Send a get node hardening response */\nstatic int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id,\n                                      const uint8_t *nodes_data, uint16_t nodes_data_length)\n{\n    if (!ip_isset(&sendto->ip_port.ip))\n        return -1;\n\n    uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];\n    uint8_t data[1 + crypto_box_PUBLICKEYBYTES + nodes_data_length];\n    data[0] = CHECK_TYPE_GETNODE_RES;\n    memcpy(data + 1, queried_client_id, crypto_box_PUBLICKEYBYTES);\n    memcpy(data + 1 + crypto_box_PUBLICKEYBYTES, nodes_data, nodes_data_length);\n    int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data,\n                             sizeof(data), CRYPTO_PACKET_HARDENING);\n\n    if (len == -1)\n        return -1;\n\n    return sendpacket(dht->net, sendto->ip_port, packet, len);\n}\n\n/* TODO: improve */\nstatic IPPTsPng *get_closelist_IPPTsPng(DHT *dht, const uint8_t *public_key, sa_family_t sa_family)\n{\n    uint32_t i;\n\n    for (i = 0; i < LCLIENT_LIST; ++i) {\n        if (public_key_cmp(dht->close_clientlist[i].public_key, public_key) != 0)\n            continue;\n\n        if (sa_family == AF_INET)\n            return &dht->close_clientlist[i].assoc4;\n        else if (sa_family == AF_INET6)\n            return &dht->close_clientlist[i].assoc6;\n    }\n\n    return NULL;\n}\n\n/*\n * check how many nodes in nodes are also present in the closelist.\n * TODO: make this function better.\n */\nstatic uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num)\n{\n    uint32_t counter = 0;\n    uint32_t i;\n\n    for (i = 0; i < num; ++i) {\n        if (id_equal(nodes[i].public_key, dht->self_public_key)) {\n            ++counter;\n            continue;\n        }\n\n        IPPTsPng *temp = get_closelist_IPPTsPng(dht, nodes[i].public_key, nodes[i].ip_port.ip.family);\n\n        if (temp) {\n            if (!is_timeout(temp->timestamp, BAD_NODE_TIMEOUT)) {\n                ++counter;\n            }\n        }\n    }\n\n    return counter;\n}\n\n/* Interval in seconds between hardening checks */\n#define HARDENING_INTERVAL 120\n#define HARDEN_TIMEOUT 1200\n\n/* Handle a received hardening packet */\nstatic int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet,\n                            uint16_t length)\n{\n    DHT *dht = object;\n\n    if (length < 2) {\n        return 1;\n    }\n\n    switch (packet[0]) {\n        case CHECK_TYPE_GETNODE_REQ: {\n            if (length != HARDREQ_DATA_SIZE)\n                return 1;\n\n            Node_format node, tocheck_node;\n            node.ip_port = source;\n            memcpy(node.public_key, source_pubkey, crypto_box_PUBLICKEYBYTES);\n            memcpy(&tocheck_node, packet + 1, sizeof(Node_format));\n\n            if (getnodes(dht, tocheck_node.ip_port, tocheck_node.public_key, packet + 1 + sizeof(Node_format), &node) == -1)\n                return 1;\n\n            return 0;\n        }\n\n        case CHECK_TYPE_GETNODE_RES: {\n            if (length <= crypto_box_PUBLICKEYBYTES + 1)\n                return 1;\n\n            if (length > 1 + crypto_box_PUBLICKEYBYTES + sizeof(Node_format) * MAX_SENT_NODES)\n                return 1;\n\n            uint16_t length_nodes = length - 1 - crypto_box_PUBLICKEYBYTES;\n            Node_format nodes[MAX_SENT_NODES];\n            int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, packet + 1 + crypto_box_PUBLICKEYBYTES, length_nodes, 0);\n\n            /* TODO: MAX_SENT_NODES nodes should be returned at all times\n             (right now we have a small network size so it could cause problems for testing and etc..) */\n            if (num_nodes <= 0)\n                return 1;\n\n            /* NOTE: This should work for now but should be changed to something better. */\n            if (have_nodes_closelist(dht, nodes, num_nodes) < (uint32_t)((num_nodes + 2) / 2))\n                return 1;\n\n            IPPTsPng *temp = get_closelist_IPPTsPng(dht, packet + 1, nodes[0].ip_port.ip.family);\n\n            if (temp == NULL)\n                return 1;\n\n            if (is_timeout(temp->hardening.send_nodes_timestamp, HARDENING_INTERVAL))\n                return 1;\n\n            if (public_key_cmp(temp->hardening.send_nodes_pingedid, source_pubkey) != 0)\n                return 1;\n\n            /* If Nodes look good and the request checks out */\n            temp->hardening.send_nodes_ok = 1;\n            return 0;/* success*/\n        }\n    }\n\n    return 1;\n}\n\n/* Return a random node from all the nodes we are connected to.\n * TODO: improve this function.\n */\nNode_format random_node(DHT *dht, sa_family_t sa_family)\n{\n    uint8_t id[crypto_box_PUBLICKEYBYTES];\n    uint32_t i;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES / 4; ++i) { /* populate the id with pseudorandom bytes.*/\n        uint32_t t = rand();\n        memcpy(id + i * sizeof(t), &t, sizeof(t));\n    }\n\n    Node_format nodes_list[MAX_SENT_NODES];\n    memset(nodes_list, 0, sizeof(nodes_list));\n    uint32_t num_nodes = get_close_nodes(dht, id, nodes_list, sa_family, 1, 0);\n\n    if (num_nodes == 0)\n        return nodes_list[0];\n    else\n        return nodes_list[rand() % num_nodes];\n}\n\n/* Put up to max_num nodes in nodes from the closelist.\n *\n * return the number of nodes.\n */\nuint16_t list_nodes(Client_data *list, unsigned int length, Node_format *nodes, uint16_t max_num)\n{\n    if (max_num == 0)\n        return 0;\n\n    uint16_t count = 0;\n\n    unsigned int i;\n\n    for (i = length; i != 0; --i) {\n        IPPTsPng *assoc = NULL;\n\n        if (!is_timeout(list[i - 1].assoc4.timestamp, BAD_NODE_TIMEOUT))\n            assoc = &list[i - 1].assoc4;\n\n        if (!is_timeout(list[i - 1].assoc6.timestamp, BAD_NODE_TIMEOUT)) {\n            if (assoc == NULL)\n                assoc = &list[i - 1].assoc6;\n            else if (rand() % 2)\n                assoc = &list[i - 1].assoc6;\n        }\n\n        if (assoc != NULL) {\n            memcpy(nodes[count].public_key, list[i - 1].public_key, crypto_box_PUBLICKEYBYTES);\n            nodes[count].ip_port = assoc->ip_port;\n            ++count;\n\n            if (count >= max_num)\n                return count;\n        }\n    }\n\n    return count;\n}\n\n/* Put up to max_num nodes in nodes from the random friends.\n *\n * return the number of nodes.\n */\nuint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num)\n{\n    if (max_num == 0)\n        return 0;\n\n    uint16_t count = 0;\n    unsigned int i, r = rand();\n\n    for (i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {\n        count += list_nodes(dht->friends_list[(i + r) % DHT_FAKE_FRIEND_NUMBER].client_list, MAX_FRIEND_CLIENTS, nodes + count,\n                            max_num - count);\n\n        if (count >= max_num)\n            break;\n    }\n\n    return count;\n}\n\n/* Put up to max_num nodes in nodes from the closelist.\n *\n * return the number of nodes.\n */\nuint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num)\n{\n    return list_nodes(dht->close_clientlist, LCLIENT_LIST, nodes, max_num);\n}\n\nvoid do_hardening(DHT *dht)\n{\n    uint32_t i;\n\n    for (i = 0; i < LCLIENT_LIST * 2; ++i) {\n        IPPTsPng  *cur_iptspng;\n        sa_family_t sa_family;\n        uint8_t   *public_key = dht->close_clientlist[i / 2].public_key;\n\n        if (i % 2 == 0) {\n            cur_iptspng = &dht->close_clientlist[i / 2].assoc4;\n            sa_family = AF_INET;\n        } else {\n            cur_iptspng = &dht->close_clientlist[i / 2].assoc6;\n            sa_family = AF_INET6;\n        }\n\n        if (is_timeout(cur_iptspng->timestamp, BAD_NODE_TIMEOUT))\n            continue;\n\n        if (cur_iptspng->hardening.send_nodes_ok == 0) {\n            if (is_timeout(cur_iptspng->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) {\n                Node_format rand_node = random_node(dht, sa_family);\n\n                if (!ipport_isset(&rand_node.ip_port))\n                    continue;\n\n                if (id_equal(public_key, rand_node.public_key))\n                    continue;\n\n                Node_format to_test;\n                to_test.ip_port = cur_iptspng->ip_port;\n                memcpy(to_test.public_key, public_key, crypto_box_PUBLICKEYBYTES);\n\n                //TODO: The search id should maybe not be ours?\n                if (send_hardening_getnode_req(dht, &rand_node, &to_test, dht->self_public_key) > 0) {\n                    memcpy(cur_iptspng->hardening.send_nodes_pingedid, rand_node.public_key, crypto_box_PUBLICKEYBYTES);\n                    cur_iptspng->hardening.send_nodes_timestamp = unix_time();\n                }\n            }\n        } else {\n            if (is_timeout(cur_iptspng->hardening.send_nodes_timestamp, HARDEN_TIMEOUT)) {\n                cur_iptspng->hardening.send_nodes_ok = 0;\n            }\n        }\n\n        //TODO: add the 2 other testers.\n    }\n}\n\n/*----------------------------------------------------------------------------------*/\n\nvoid cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object)\n{\n    dht->cryptopackethandlers[byte].function = cb;\n    dht->cryptopackethandlers[byte].object = object;\n}\n\nstatic int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    DHT *dht = object;\n\n    if (packet[0] == NET_PACKET_CRYPTO) {\n        if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES ||\n                length > MAX_CRYPTO_REQUEST_SIZE + crypto_box_MACBYTES)\n            return 1;\n\n        if (public_key_cmp(packet + 1, dht->self_public_key) == 0) { // Check if request is for us.\n            uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n            uint8_t data[MAX_CRYPTO_REQUEST_SIZE];\n            uint8_t number;\n            int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length);\n\n            if (len == -1 || len == 0)\n                return 1;\n\n            if (!dht->cryptopackethandlers[number].function) return 1;\n\n            return dht->cryptopackethandlers[number].function(dht->cryptopackethandlers[number].object, source, public_key,\n                    data, len);\n\n        } else { /* If request is not for us, try routing it. */\n            int retval = route_packet(dht, packet + 1, packet, length);\n\n            if ((unsigned int)retval == length)\n                return 0;\n        }\n    }\n\n    return 1;\n}\n\n/*----------------------------------------------------------------------------------*/\n\nDHT *new_DHT(Networking_Core *net)\n{\n    /* init time */\n    unix_time_update();\n\n    if (net == NULL)\n        return NULL;\n\n    DHT *dht = calloc(1, sizeof(DHT));\n\n    if (dht == NULL)\n        return NULL;\n\n    dht->net = net;\n    dht->ping = new_ping(dht);\n\n    if (dht->ping == NULL) {\n        kill_DHT(dht);\n        return NULL;\n    }\n\n    networking_registerhandler(dht->net, NET_PACKET_GET_NODES, &handle_getnodes, dht);\n    networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht);\n    networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht);\n    cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht);\n    cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, &handle_hardening, dht);\n\n    new_symmetric_key(dht->secret_symmetric_key);\n    crypto_box_keypair(dht->self_public_key, dht->self_secret_key);\n\n    ping_array_init(&dht->dht_ping_array, DHT_PING_ARRAY_SIZE, PING_TIMEOUT);\n    ping_array_init(&dht->dht_harden_ping_array, DHT_PING_ARRAY_SIZE, PING_TIMEOUT);\n#ifdef ENABLE_ASSOC_DHT\n    dht->assoc = new_Assoc_default(dht->self_public_key);\n#endif\n    uint32_t i;\n\n    for (i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {\n        uint8_t random_key_bytes[crypto_box_PUBLICKEYBYTES];\n        randombytes(random_key_bytes, sizeof(random_key_bytes));\n\n        if (DHT_addfriend(dht, random_key_bytes, 0, 0, 0, 0) != 0) {\n            kill_DHT(dht);\n            return NULL;\n        }\n    }\n\n    return dht;\n}\n\nvoid do_DHT(DHT *dht)\n{\n    unix_time_update();\n\n    if (dht->last_run == unix_time()) {\n        return;\n    }\n\n    // Load friends/clients if first call to do_DHT\n    if (dht->loaded_num_nodes) {\n        DHT_connect_after_load(dht);\n    }\n\n    do_Close(dht);\n    do_DHT_friends(dht);\n    do_NAT(dht);\n    do_to_ping(dht->ping);\n    //do_hardening(dht);\n#ifdef ENABLE_ASSOC_DHT\n\n    if (dht->assoc)\n        do_Assoc(dht->assoc, dht);\n\n#endif\n    dht->last_run = unix_time();\n}\nvoid kill_DHT(DHT *dht)\n{\n#ifdef ENABLE_ASSOC_DHT\n    kill_Assoc(dht->assoc);\n#endif\n    networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL);\n    networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL);\n    cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL);\n    cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL);\n    ping_array_free_all(&dht->dht_ping_array);\n    ping_array_free_all(&dht->dht_harden_ping_array);\n    kill_ping(dht->ping);\n    free(dht->friends_list);\n    free(dht->loaded_nodes_list);\n    free(dht);\n}\n\n/* new DHT format for load/save, more robust and forward compatible */\n//TODO: Move this closer to Messenger.\n#define DHT_STATE_COOKIE_GLOBAL 0x159000d\n\n#define DHT_STATE_COOKIE_TYPE      0x11ce\n#define DHT_STATE_TYPE_NODES       4\n\n#define MAX_SAVED_DHT_NODES (((DHT_FAKE_FRIEND_NUMBER * MAX_FRIEND_CLIENTS) + LCLIENT_LIST) * 2)\n\n/* Get the size of the DHT (for saving). */\nuint32_t DHT_size(const DHT *dht)\n{\n    uint32_t numv4 = 0, numv6 = 0, i, j;\n\n    for (i = 0; i < LCLIENT_LIST; ++i) {\n        numv4 += (dht->close_clientlist[i].assoc4.timestamp != 0);\n        numv6 += (dht->close_clientlist[i].assoc6.timestamp != 0);\n    }\n\n    for (i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) {\n        DHT_Friend *fr = &dht->friends_list[i];\n\n        for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {\n            numv4 += (fr->client_list[j].assoc4.timestamp != 0);\n            numv6 += (fr->client_list[j].assoc6.timestamp != 0);\n        }\n    }\n\n    uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2;\n\n    return size32 + sizesubhead + (packed_node_size(AF_INET) * numv4) + (packed_node_size(AF_INET6) * numv6);\n}\n\nstatic uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t type)\n{\n    host_to_lendian32(data, len);\n    data += sizeof(uint32_t);\n    host_to_lendian32(data, (host_tolendian16(DHT_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type));\n    data += sizeof(uint32_t);\n    return data;\n}\n\n\n/* Save the DHT in data where data is an array of size DHT_size(). */\nvoid DHT_save(DHT *dht, uint8_t *data)\n{\n    host_to_lendian32(data,  DHT_STATE_COOKIE_GLOBAL);\n    data += sizeof(uint32_t);\n\n    uint32_t num, i, j;\n\n    uint8_t *old_data = data;\n\n    /* get right offset. we write the actual header later. */\n    data = z_state_save_subheader(data, 0, 0);\n\n    Node_format clients[MAX_SAVED_DHT_NODES];\n\n    for (num = 0, i = 0; i < LCLIENT_LIST; ++i) {\n        if (dht->close_clientlist[i].assoc4.timestamp != 0) {\n            memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, crypto_box_PUBLICKEYBYTES);\n            clients[num].ip_port = dht->close_clientlist[i].assoc4.ip_port;\n            ++num;\n        }\n\n        if (dht->close_clientlist[i].assoc6.timestamp != 0) {\n            memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, crypto_box_PUBLICKEYBYTES);\n            clients[num].ip_port = dht->close_clientlist[i].assoc6.ip_port;\n            ++num;\n        }\n    }\n\n    for (i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) {\n        DHT_Friend *fr = &dht->friends_list[i];\n\n        for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {\n            if (fr->client_list[j].assoc4.timestamp != 0) {\n                memcpy(clients[num].public_key, fr->client_list[j].public_key, crypto_box_PUBLICKEYBYTES);\n                clients[num].ip_port = fr->client_list[j].assoc4.ip_port;\n                ++num;\n            }\n\n            if (fr->client_list[j].assoc6.timestamp != 0) {\n                memcpy(clients[num].public_key, fr->client_list[j].public_key, crypto_box_PUBLICKEYBYTES);\n                clients[num].ip_port = fr->client_list[j].assoc6.ip_port;\n                ++num;\n            }\n        }\n    }\n\n    z_state_save_subheader(old_data, pack_nodes(data, sizeof(Node_format) * num, clients, num), DHT_STATE_TYPE_NODES);\n}\n\n/* Bootstrap from this number of nodes every time DHT_connect_after_load() is called */\n#define SAVE_BOOTSTAP_FREQUENCY 8\n\n/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set */\nint DHT_connect_after_load(DHT *dht)\n{\n    if (dht == NULL)\n        return -1;\n\n    if (!dht->loaded_nodes_list)\n        return -1;\n\n    /* DHT is connected, stop. */\n    if (DHT_non_lan_connected(dht)) {\n        free(dht->loaded_nodes_list);\n        dht->loaded_nodes_list = NULL;\n        dht->loaded_num_nodes = 0;\n        return 0;\n    }\n\n    unsigned int i;\n\n    for (i = 0; i < dht->loaded_num_nodes && i < SAVE_BOOTSTAP_FREQUENCY; ++i) {\n        unsigned int index = dht->loaded_nodes_index % dht->loaded_num_nodes;\n        DHT_bootstrap(dht, dht->loaded_nodes_list[index].ip_port, dht->loaded_nodes_list[index].public_key);\n        ++dht->loaded_nodes_index;\n    }\n\n    return 0;\n}\n\nstatic int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)\n{\n    DHT *dht = outer;\n\n    switch (type) {\n        case DHT_STATE_TYPE_NODES:\n            if (length == 0)\n                break;\n\n            {\n                free(dht->loaded_nodes_list);\n                // Copy to loaded_clients_list\n                dht->loaded_nodes_list = calloc(MAX_SAVED_DHT_NODES, sizeof(Node_format));\n\n                int num = unpack_nodes(dht->loaded_nodes_list, MAX_SAVED_DHT_NODES, NULL, data, length, 0);\n\n                if (num > 0) {\n                    dht->loaded_num_nodes = num;\n                } else {\n                    dht->loaded_num_nodes = 0;\n                }\n\n            } /* localize declarations */\n\n            break;\n\n#ifdef DEBUG\n\n        default:\n            fprintf(stderr, \"Load state (DHT): contains unrecognized part (len %u, type %u)\\n\",\n                    length, type);\n            break;\n#endif\n    }\n\n    return 0;\n}\n\n/* Load the DHT from data of size size.\n *\n *  return -1 if failure.\n *  return 0 if success.\n */\nint DHT_load(DHT *dht, const uint8_t *data, uint32_t length)\n{\n    uint32_t cookie_len = sizeof(uint32_t);\n\n    if (length > cookie_len) {\n        uint32_t data32;\n        lendian_to_host32(&data32, data);\n\n        if (data32 == DHT_STATE_COOKIE_GLOBAL)\n            return load_state(dht_load_state_callback, dht, data + cookie_len,\n                              length - cookie_len, DHT_STATE_COOKIE_TYPE);\n    }\n\n    return -1;\n}\n\n/*  return 0 if we are not connected to the DHT.\n *  return 1 if we are.\n */\nint DHT_isconnected(const DHT *dht)\n{\n    uint32_t i;\n    unix_time_update();\n\n    for (i = 0; i < LCLIENT_LIST; ++i) {\n        const Client_data *client = &dht->close_clientlist[i];\n\n        if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) ||\n                !is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT))\n            return 1;\n    }\n\n    return 0;\n}\n\n/*  return 0 if we are not connected or only connected to lan peers with the DHT.\n *  return 1 if we are.\n */\nint DHT_non_lan_connected(const DHT *dht)\n{\n    uint32_t i;\n    unix_time_update();\n\n    for (i = 0; i < LCLIENT_LIST; ++i) {\n        const Client_data *client = &dht->close_clientlist[i];\n\n        if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && LAN_ip(client->assoc4.ip_port.ip) == -1)\n            return 1;\n\n        if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) && LAN_ip(client->assoc6.ip_port.ip) == -1)\n            return 1;\n\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "toxcore/DHT.h",
    "content": "/* DHT.h\n *\n * An implementation of the DHT as seen in docs/updates/DHT.md\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef DHT_H\n#define DHT_H\n\n#include \"crypto_core.h\"\n#include \"network.h\"\n#include \"ping_array.h\"\n\n/* Maximum number of clients stored per friend. */\n#define MAX_FRIEND_CLIENTS 8\n\n#define LCLIENT_NODES (MAX_FRIEND_CLIENTS)\n#define LCLIENT_LENGTH 128\n\n/* A list of the clients mathematically closest to ours. */\n#define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES)\n\n#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8\n\n/* The max number of nodes to send with send nodes. */\n#define MAX_SENT_NODES 4\n\n/* Ping timeout in seconds */\n#define PING_TIMEOUT 5\n\n/* size of DHT ping arrays. */\n#define DHT_PING_ARRAY_SIZE 512\n\n/* Ping interval in seconds for each node in our lists. */\n#define PING_INTERVAL 60\n\n/* The number of seconds for a non responsive node to become bad. */\n#define PINGS_MISSED_NODE_GOES_BAD 1\n#define PING_ROUNDTRIP 2\n#define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * (PING_INTERVAL + PING_ROUNDTRIP))\n\n/* Redefinitions of variables for safe transfer over wire. */\n#define TOX_AF_INET 2\n#define TOX_AF_INET6 10\n#define TOX_TCP_INET 130\n#define TOX_TCP_INET6 138\n\n/* The number of \"fake\" friends to add (for optimization purposes and so our paths for the onion part are more random) */\n#define DHT_FAKE_FRIEND_NUMBER 2\n\n/* Functions to transfer ips safely across wire. */\nvoid to_net_family(IP *ip);\n\n/* return 0 on success, -1 on failure. */\nint to_host_family(IP *ip);\n\ntypedef struct {\n    IP_Port     ip_port;\n    uint64_t    timestamp;\n} IPPTs;\n\ntypedef struct {\n    /* Node routes request correctly (true (1) or false/didn't check (0)) */\n    uint8_t     routes_requests_ok;\n    /* Time which we last checked this.*/\n    uint64_t    routes_requests_timestamp;\n    uint8_t     routes_requests_pingedid[crypto_box_PUBLICKEYBYTES];\n    /* Node sends correct send_node (true (1) or false/didn't check (0)) */\n    uint8_t     send_nodes_ok;\n    /* Time which we last checked this.*/\n    uint64_t    send_nodes_timestamp;\n    uint8_t     send_nodes_pingedid[crypto_box_PUBLICKEYBYTES];\n    /* Node can be used to test other nodes (true (1) or false/didn't check (0)) */\n    uint8_t     testing_requests;\n    /* Time which we last checked this.*/\n    uint64_t    testing_timestamp;\n    uint8_t     testing_pingedid[crypto_box_PUBLICKEYBYTES];\n} Hardening;\n\ntypedef struct {\n    IP_Port     ip_port;\n    uint64_t    timestamp;\n    uint64_t    last_pinged;\n\n    Hardening hardening;\n    /* Returned by this node. Either our friend or us. */\n    IP_Port     ret_ip_port;\n    uint64_t    ret_timestamp;\n} IPPTsPng;\n\ntypedef struct {\n    uint8_t     public_key[crypto_box_PUBLICKEYBYTES];\n    IPPTsPng    assoc4;\n    IPPTsPng    assoc6;\n} Client_data;\n\n/*----------------------------------------------------------------------------------*/\n\ntypedef struct {\n    /* 1 if currently hole punching, otherwise 0 */\n    uint8_t     hole_punching;\n    uint32_t    punching_index;\n    uint32_t    tries;\n    uint32_t    punching_index2;\n\n    uint64_t    punching_timestamp;\n    uint64_t    recvNATping_timestamp;\n    uint64_t    NATping_id;\n    uint64_t    NATping_timestamp;\n} NAT;\n\n#define DHT_FRIEND_MAX_LOCKS 32\n\ntypedef struct {\n    uint8_t     public_key[crypto_box_PUBLICKEYBYTES];\n    IP_Port     ip_port;\n}\nNode_format;\n\ntypedef struct {\n    uint8_t     public_key[crypto_box_PUBLICKEYBYTES];\n    Client_data client_list[MAX_FRIEND_CLIENTS];\n\n    /* Time at which the last get_nodes request was sent. */\n    uint64_t    lastgetnode;\n    /* number of times get_node packets were sent. */\n    uint32_t    bootstrap_times;\n\n    /* Symetric NAT hole punching stuff. */\n    NAT         nat;\n\n    uint16_t lock_count;\n    struct {\n        void (*ip_callback)(void *, int32_t, IP_Port);\n        void *data;\n        int32_t number;\n    } callbacks[DHT_FRIEND_MAX_LOCKS];\n\n    Node_format to_bootstrap[MAX_SENT_NODES];\n    unsigned int num_to_bootstrap;\n} DHT_Friend;\n\n/* Return packet size of packed node with ip_family on success.\n * Return -1 on failure.\n */\nint packed_node_size(uint8_t ip_family);\n\n/* Pack number of nodes into data of maxlength length.\n *\n * return length of packed nodes on success.\n * return -1 on failure.\n */\nint pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number);\n\n/* Unpack data of length into nodes of size max_num_nodes.\n * Put the length of the data processed in processed_data_len.\n * tcp_enabled sets if TCP nodes are expected (true) or not (false).\n *\n * return number of unpacked nodes on success.\n * return -1 on failure.\n */\nint unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,\n                 uint16_t length, uint8_t tcp_enabled);\n\n\n/*----------------------------------------------------------------------------------*/\n/* struct to store some shared keys so we don't have to regenerate them for each request. */\n#define MAX_KEYS_PER_SLOT 4\n#define KEYS_TIMEOUT 600\ntypedef struct {\n    struct {\n        uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n        uint8_t shared_key[crypto_box_BEFORENMBYTES];\n        uint32_t times_requested;\n        uint8_t  stored; /* 0 if not, 1 if is */\n        uint64_t time_last_requested;\n    } keys[256 * MAX_KEYS_PER_SLOT];\n} Shared_Keys;\n\n/*----------------------------------------------------------------------------------*/\n\ntypedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, const uint8_t *source_pubkey,\n        const uint8_t *data, uint16_t len);\n\ntypedef struct {\n    cryptopacket_handler_callback function;\n    void *object;\n} Cryptopacket_Handles;\n\ntypedef struct {\n    Networking_Core *net;\n\n    Client_data    close_clientlist[LCLIENT_LIST];\n    uint64_t       close_lastgetnodes;\n    uint32_t       close_bootstrap_times;\n\n    /* Note: this key should not be/is not used to transmit any sensitive materials */\n    uint8_t      secret_symmetric_key[crypto_box_KEYBYTES];\n    /* DHT keypair */\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n\n    DHT_Friend    *friends_list;\n    uint16_t       num_friends;\n\n    Node_format   *loaded_nodes_list;\n    uint32_t       loaded_num_nodes;\n    unsigned int   loaded_nodes_index;\n\n    Shared_Keys shared_keys_recv;\n    Shared_Keys shared_keys_sent;\n\n    struct PING   *ping;\n    Ping_Array    dht_ping_array;\n    Ping_Array    dht_harden_ping_array;\n#ifdef ENABLE_ASSOC_DHT\n    struct Assoc  *assoc;\n#endif\n    uint64_t       last_run;\n\n    Cryptopacket_Handles cryptopackethandlers[256];\n\n    Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES];\n    unsigned int num_to_bootstrap;\n} DHT;\n/*----------------------------------------------------------------------------------*/\n\n/* Shared key generations are costly, it is therefor smart to store commonly used\n * ones so that they can re used later without being computed again.\n *\n * If shared key is already in shared_keys, copy it to shared_key.\n * else generate it into shared_key and copy it to shared_keys\n */\nvoid get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, const uint8_t *secret_key,\n                    const uint8_t *public_key);\n\n/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key\n * for packets that we receive.\n */\nvoid DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);\n\n/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key\n * for packets that we send.\n */\nvoid DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);\n\nvoid DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id);\n\n/* Add a new friend to the friends list.\n * public_key must be crypto_box_PUBLICKEYBYTES bytes long.\n *\n * ip_callback is the callback of a function that will be called when the ip address\n * is found along with arguments data and number.\n *\n * lock_count will be set to a non zero number that must be passed to DHT_delfriend()\n * to properly remove the callback.\n *\n *  return 0 if success.\n *  return -1 if failure (friends list is full).\n */\nint DHT_addfriend(DHT *dht, const uint8_t *public_key, void (*ip_callback)(void *data, int32_t number, IP_Port),\n                  void *data, int32_t number, uint16_t *lock_count);\n\n/* Delete a friend from the friends list.\n * public_key must be crypto_box_PUBLICKEYBYTES bytes long.\n *\n *  return 0 if success.\n *  return -1 if failure (public_key not in friends list).\n */\nint DHT_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count);\n\n/* Get ip of friend.\n *  public_key must be crypto_box_PUBLICKEYBYTES bytes long.\n *  ip must be 4 bytes long.\n *  port must be 2 bytes long.\n *\n * int DHT_getfriendip(DHT *dht, uint8_t *public_key, IP_Port *ip_port);\n *\n *  return -1, -- if public_key does NOT refer to a friend\n *  return  0, -- if public_key refers to a friend and we failed to find the friend (yet)\n *  return  1, ip if public_key refers to a friend and we found him\n */\nint DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port);\n\n/* Compares pk1 and pk2 with pk.\n *\n *  return 0 if both are same distance.\n *  return 1 if pk1 is closer.\n *  return 2 if pk2 is closer.\n */\nint id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2);\n\n/* Add node to the node list making sure only the nodes closest to cmp_pk are in the list.\n */\n_Bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port,\n                  const uint8_t *cmp_pk);\n\n/* Return 1 if node can be added to close list, 0 if it can't.\n */\n_Bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port);\n\n/* Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know\n * and put them in nodes_list (must be MAX_SENT_NODES big).\n *\n * sa_family = family (IPv4 or IPv6) (0 if we don't care)?\n * is_LAN = return some LAN ips (true or false)\n * want_good = do we want tested nodes or not? (TODO)\n *\n * return the number of nodes returned.\n *\n */\nint get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, sa_family_t sa_family,\n                    uint8_t is_LAN, uint8_t want_good);\n\n\n/* Put up to max_num nodes in nodes from the random friends.\n *\n * return the number of nodes.\n */\nuint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num);\n\n/* Put up to max_num nodes in nodes from the closelist.\n *\n * return the number of nodes.\n */\nuint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num);\n\n/* Run this function at least a couple times per second (It's the main loop). */\nvoid do_DHT(DHT *dht);\n\n/*\n *  Use these two functions to bootstrap the client.\n */\n/* Sends a \"get nodes\" request to the given node with ip, port and public_key\n *   to setup connections\n */\nvoid DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key);\n/* Resolves address into an IP address. If successful, sends a \"get nodes\"\n *   request to the given node with ip, port and public_key to setup connections\n *\n * address can be a hostname or an IP address (IPv4 or IPv6).\n * if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses\n * if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first,\n *   then IPv4 addresses.\n *\n *  returns 1 if the address could be converted into an IP address\n *  returns 0 otherwise\n */\nint DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,\n                               uint16_t port, const uint8_t *public_key);\n\n/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set.\n *\n * returns 0 if successful\n * returns -1 otherwise\n */\nint DHT_connect_after_load(DHT *dht);\n\n/* ROUTING FUNCTIONS */\n\n/* Send the given packet to node with public_key.\n *\n *  return -1 if failure.\n */\nint route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length);\n\n/* Send the following packet to everyone who tells us they are connected to friend_id.\n *\n *  return number of nodes it sent the packet to.\n */\nint route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length);\n\n/* Function to handle crypto packets.\n */\nvoid cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object);\n\n/* SAVE/LOAD functions */\n\n/* Get the size of the DHT (for saving). */\nuint32_t DHT_size(const DHT *dht);\n\n/* Save the DHT in data where data is an array of size DHT_size(). */\nvoid DHT_save(DHT *dht, uint8_t *data);\n\n/* Load the DHT from data of size size.\n *\n *  return -1 if failure.\n *  return 0 if success.\n */\nint DHT_load(DHT *dht, const uint8_t *data, uint32_t length);\n\n/* Initialize DHT. */\nDHT *new_DHT(Networking_Core *net);\n\nvoid kill_DHT(DHT *dht);\n\n/*  return 0 if we are not connected to the DHT.\n *  return 1 if we are.\n */\nint DHT_isconnected(const DHT *dht);\n\n/*  return 0 if we are not connected or only connected to lan peers with the DHT.\n *  return 1 if we are.\n */\nint DHT_non_lan_connected(const DHT *dht);\n\n\nint addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key);\n\n#endif\n\n"
  },
  {
    "path": "toxcore/LAN_discovery.c",
    "content": "/*  LAN_discovery.c\n *\n *  LAN discovery implementation.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"LAN_discovery.h\"\n#include \"util.h\"\n\n/* Used for get_broadcast(). */\n#ifdef __linux\n#include <sys/ioctl.h>\n#include <arpa/inet.h>\n#include <linux/netdevice.h>\n#endif\n\n#define MAX_INTERFACES 16\n\n\nstatic int     broadcast_count = -1;\nstatic IP_Port broadcast_ip_port[MAX_INTERFACES];\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n\n#include <iphlpapi.h>\n\nstatic void fetch_broadcast_info(uint16_t port)\n{\n    broadcast_count = 0;\n\n    IP_ADAPTER_INFO *pAdapterInfo = malloc(sizeof(IP_ADAPTER_INFO));\n    unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO);\n\n    if (pAdapterInfo == NULL) {\n        return;\n    }\n\n    if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {\n        free(pAdapterInfo);\n        pAdapterInfo = malloc(ulOutBufLen);\n\n        if (pAdapterInfo == NULL) {\n            return;\n        }\n    }\n\n    int ret;\n\n    if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {\n        IP_ADAPTER_INFO *pAdapter = pAdapterInfo;\n\n        while (pAdapter) {\n            IP gateway = {0}, subnet_mask = {0};\n\n            if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask)\n                    && addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) {\n                if (gateway.family == AF_INET && subnet_mask.family == AF_INET) {\n                    IP_Port *ip_port = &broadcast_ip_port[broadcast_count];\n                    ip_port->ip.family = AF_INET;\n                    uint32_t gateway_ip = ntohl(gateway.ip4.uint32), subnet_ip = ntohl(subnet_mask.ip4.uint32);\n                    uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1;\n                    ip_port->ip.ip4.uint32 = htonl(broadcast_ip);\n                    ip_port->port = port;\n                    broadcast_count++;\n\n                    if (broadcast_count >= MAX_INTERFACES) {\n                        return;\n                    }\n                }\n            }\n\n            pAdapter = pAdapter->Next;\n        }\n    }\n\n    if (pAdapterInfo) {\n        free(pAdapterInfo);\n    }\n}\n\n#elif defined(__linux__)\n\nstatic void fetch_broadcast_info(uint16_t port)\n{\n    /* Not sure how many platforms this will run on,\n     * so it's wrapped in __linux for now.\n     * Definitely won't work like this on Windows...\n     */\n    broadcast_count = 0;\n    sock_t sock = 0;\n\n    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)\n        return;\n\n    /* Configure ifconf for the ioctl call. */\n    struct ifreq i_faces[MAX_INTERFACES];\n    memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES);\n\n    struct ifconf ifconf;\n    ifconf.ifc_buf = (char *)i_faces;\n    ifconf.ifc_len = sizeof(i_faces);\n\n    if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) {\n        close(sock);\n        return;\n    }\n\n    /* ifconf.ifc_len is set by the ioctl() to the actual length used;\n     * on usage of the complete array the call should be repeated with\n     * a larger array, not done (640kB and 16 interfaces shall be\n     * enough, for everybody!)\n     */\n    int i, count = ifconf.ifc_len / sizeof(struct ifreq);\n\n    for (i = 0; i < count; i++) {\n        /* there are interfaces with are incapable of broadcast */\n        if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0)\n            continue;\n\n        /* moot check: only AF_INET returned (backwards compat.) */\n        if (i_faces[i].ifr_broadaddr.sa_family != AF_INET)\n            continue;\n\n        struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;\n\n        if (broadcast_count >= MAX_INTERFACES) {\n            close(sock);\n            return;\n        }\n\n        IP_Port *ip_port = &broadcast_ip_port[broadcast_count];\n        ip_port->ip.family = AF_INET;\n        ip_port->ip.ip4.in_addr = sock4->sin_addr;\n\n        if (ip_port->ip.ip4.uint32 == 0) {\n            continue;\n        }\n\n        ip_port->port = port;\n        broadcast_count++;\n    }\n\n    close(sock);\n}\n\n#else //TODO: Other platforms?\n\nstatic void fetch_broadcast_info(uint16_t port)\n{\n    broadcast_count = 0;\n}\n\n#endif\n/* Send packet to all IPv4 broadcast addresses\n *\n *  return 1 if sent to at least one broadcast target.\n *  return 0 on failure to find any valid broadcast target.\n */\nstatic uint32_t send_broadcasts(Networking_Core *net, uint16_t port, const uint8_t *data, uint16_t length)\n{\n    /* fetch only once? on every packet? every X seconds?\n     * old: every packet, new: once */\n    if (broadcast_count < 0)\n        fetch_broadcast_info(port);\n\n    if (!broadcast_count)\n        return 0;\n\n    int i;\n\n    for (i = 0; i < broadcast_count; i++)\n        sendpacket(net, broadcast_ip_port[i], data, length);\n\n    return 1;\n}\n\n/* Return the broadcast ip. */\nstatic IP broadcast_ip(sa_family_t family_socket, sa_family_t family_broadcast)\n{\n    IP ip;\n    ip_reset(&ip);\n\n    if (family_socket == AF_INET6) {\n        if (family_broadcast == AF_INET6) {\n            ip.family = AF_INET6;\n            /* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */\n            /* FE80::*: MUST be exact, for that we would need to look over all\n             * interfaces and check in which status they are */\n            ip.ip6.uint8[ 0] = 0xFF;\n            ip.ip6.uint8[ 1] = 0x02;\n            ip.ip6.uint8[15] = 0x01;\n        } else if (family_broadcast == AF_INET) {\n            ip.family = AF_INET6;\n            ip.ip6.uint32[0] = 0;\n            ip.ip6.uint32[1] = 0;\n            ip.ip6.uint32[2] = htonl(0xFFFF);\n            ip.ip6.uint32[3] = INADDR_BROADCAST;\n        }\n    } else if (family_socket == AF_INET) {\n        if (family_broadcast == AF_INET) {\n            ip.family = AF_INET;\n            ip.ip4.uint32 = INADDR_BROADCAST;\n        }\n    }\n\n    return ip;\n}\n\n/* Is IP a local ip or not. */\n_Bool Local_ip(IP ip)\n{\n    if (ip.family == AF_INET) {\n        IP4 ip4 = ip.ip4;\n\n        /* Loopback. */\n        if (ip4.uint8[0] == 127)\n            return 1;\n    } else {\n        /* embedded IPv4-in-IPv6 */\n        if (IPV6_IPV4_IN_V6(ip.ip6)) {\n            IP ip4;\n            ip4.family = AF_INET;\n            ip4.ip4.uint32 = ip.ip6.uint32[3];\n            return Local_ip(ip4);\n        }\n\n        /* localhost in IPv6 (::1) */\n        if (ip.ip6.uint64[0] == 0 && ip.ip6.uint32[2] == 0 && ip.ip6.uint32[3] == htonl(1))\n            return 1;\n    }\n\n    return 0;\n}\n\n/*  return 0 if ip is a LAN ip.\n *  return -1 if it is not.\n */\nint LAN_ip(IP ip)\n{\n    if (Local_ip(ip))\n        return 0;\n\n    if (ip.family == AF_INET) {\n        IP4 ip4 = ip.ip4;\n\n        /* 10.0.0.0 to 10.255.255.255 range. */\n        if (ip4.uint8[0] == 10)\n            return 0;\n\n        /* 172.16.0.0 to 172.31.255.255 range. */\n        if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31)\n            return 0;\n\n        /* 192.168.0.0 to 192.168.255.255 range. */\n        if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168)\n            return 0;\n\n        /* 169.254.1.0 to 169.254.254.255 range. */\n        if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0\n                && ip4.uint8[2] != 255)\n            return 0;\n\n        /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)\n         * (shared address space to stack another layer of NAT) */\n        if ((ip4.uint8[0] == 100) && ((ip4.uint8[1] & 0xC0) == 0x40))\n            return 0;\n\n    } else if (ip.family == AF_INET6) {\n\n        /* autogenerated for each interface: FE80::* (up to FEBF::*)\n           FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */\n        if (((ip.ip6.uint8[0] == 0xFF) && (ip.ip6.uint8[1] < 3) && (ip.ip6.uint8[15] == 1)) ||\n                ((ip.ip6.uint8[0] == 0xFE) && ((ip.ip6.uint8[1] & 0xC0) == 0x80)))\n            return 0;\n\n        /* embedded IPv4-in-IPv6 */\n        if (IPV6_IPV4_IN_V6(ip.ip6)) {\n            IP ip4;\n            ip4.family = AF_INET;\n            ip4.ip4.uint32 = ip.ip6.uint32[3];\n            return LAN_ip(ip4);\n        }\n    }\n\n    return -1;\n}\n\nstatic int handle_LANdiscovery(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    DHT *dht = object;\n\n    if (LAN_ip(source.ip) == -1)\n        return 1;\n\n    if (length != crypto_box_PUBLICKEYBYTES + 1)\n        return 1;\n\n    DHT_bootstrap(dht, source, packet + 1);\n    return 0;\n}\n\n\nint send_LANdiscovery(uint16_t port, DHT *dht)\n{\n    uint8_t data[crypto_box_PUBLICKEYBYTES + 1];\n    data[0] = NET_PACKET_LAN_DISCOVERY;\n    id_copy(data + 1, dht->self_public_key);\n\n    send_broadcasts(dht->net, port, data, 1 + crypto_box_PUBLICKEYBYTES);\n\n    int res = -1;\n    IP_Port ip_port;\n    ip_port.port = port;\n\n    /* IPv6 multicast */\n    if (dht->net->family == AF_INET6) {\n        ip_port.ip = broadcast_ip(AF_INET6, AF_INET6);\n\n        if (ip_isset(&ip_port.ip))\n            if (sendpacket(dht->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES) > 0)\n                res = 1;\n    }\n\n    /* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is AF_INET6 */\n    ip_port.ip = broadcast_ip(dht->net->family, AF_INET);\n\n    if (ip_isset(&ip_port.ip))\n        if (sendpacket(dht->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES))\n            res = 1;\n\n    return res;\n}\n\n\nvoid LANdiscovery_init(DHT *dht)\n{\n    networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, &handle_LANdiscovery, dht);\n}\n\nvoid LANdiscovery_kill(DHT *dht)\n{\n    networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, NULL, NULL);\n}\n"
  },
  {
    "path": "toxcore/LAN_discovery.h",
    "content": "/*  LAN_discovery.h\n *\n *  LAN discovery implementation.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n\n#ifndef LAN_DISCOVERY_H\n#define LAN_DISCOVERY_H\n\n\n#include \"DHT.h\"\n\n/* Interval in seconds between LAN discovery packet sending. */\n#define LAN_DISCOVERY_INTERVAL 10\n\n/* Send a LAN discovery pcaket to the broadcast address with port port. */\nint send_LANdiscovery(uint16_t port, DHT *dht);\n\n/* Sets up packet handlers. */\nvoid LANdiscovery_init(DHT *dht);\n\n/* Clear packet handlers. */\nvoid LANdiscovery_kill(DHT *dht);\n\n/* Is IP a local ip or not. */\n_Bool Local_ip(IP ip);\n\n/* checks if a given IP isn't routable\n *\n *  return 0 if ip is a LAN ip.\n *  return -1 if it is not.\n */\nint LAN_ip(IP ip);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/Makefile.inc",
    "content": "lib_LTLIBRARIES += libtoxcore.la\n\nlibtoxcore_la_include_HEADERS = \\\n                        ../toxcore/tox.h \\\n                        ../toxcore/tox_old.h\n\nlibtoxcore_la_includedir = $(includedir)/tox\n\nlibtoxcore_la_SOURCES = ../toxcore/DHT.h \\\n                        ../toxcore/DHT.c \\\n                        ../toxcore/network.h \\\n                        ../toxcore/network.c \\\n                        ../toxcore/crypto_core.h \\\n                        ../toxcore/crypto_core.c \\\n                        ../toxcore/ping_array.h \\\n                        ../toxcore/ping_array.c \\\n                        ../toxcore/net_crypto.h \\\n                        ../toxcore/net_crypto.c \\\n                        ../toxcore/friend_requests.h \\\n                        ../toxcore/friend_requests.c \\\n                        ../toxcore/LAN_discovery.h \\\n                        ../toxcore/LAN_discovery.c \\\n                        ../toxcore/friend_connection.h \\\n                        ../toxcore/friend_connection.c \\\n                        ../toxcore/Messenger.h \\\n                        ../toxcore/Messenger.c \\\n                        ../toxcore/ping.h \\\n                        ../toxcore/ping.c \\\n                        ../toxcore/tox.h \\\n                        ../toxcore/tox.c \\\n                        ../toxcore/util.h \\\n                        ../toxcore/util.c \\\n                        ../toxcore/group.h \\\n                        ../toxcore/group.c \\\n                        ../toxcore/assoc.h \\\n                        ../toxcore/assoc.c \\\n                        ../toxcore/onion.h \\\n                        ../toxcore/onion.c \\\n                        ../toxcore/logger.h \\\n                        ../toxcore/logger.c \\\n                        ../toxcore/onion_announce.h \\\n                        ../toxcore/onion_announce.c \\\n                        ../toxcore/onion_client.h \\\n                        ../toxcore/onion_client.c \\\n                        ../toxcore/TCP_client.h \\\n                        ../toxcore/TCP_client.c \\\n                        ../toxcore/TCP_server.h \\\n                        ../toxcore/TCP_server.c \\\n                        ../toxcore/TCP_connection.h \\\n                        ../toxcore/TCP_connection.c \\\n                        ../toxcore/list.c \\\n                        ../toxcore/list.h \\\n                        ../toxcore/misc_tools.h \\\n                        ../toxcore/tox_old_code.h\n\nlibtoxcore_la_CFLAGS =  -I$(top_srcdir) \\\n                        -I$(top_srcdir)/toxcore \\\n                        $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS) \\\n                        $(PTHREAD_CFLAGS)\n\nlibtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \\\n                        $(EXTRA_LT_LDFLAGS) \\\n                        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        $(MATH_LDFLAGS) \\\n                        $(RT_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\nlibtoxcore_la_LIBADD =  $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NAC_LIBS) \\\n                        $(PTHREAD_LIBS)\n"
  },
  {
    "path": "toxcore/Messenger.c",
    "content": "/* Messenger.c\n *\n * An implementation of a simple text chat only messenger on the tox network core.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#ifdef DEBUG\n#include <assert.h>\n#endif\n\n#include \"logger.h\"\n#include \"Messenger.h\"\n#include \"assoc.h\"\n#include \"network.h\"\n#include \"util.h\"\n\n\nstatic void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status);\nstatic int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,\n                                uint32_t length, uint8_t congestion_control);\n\n// friend_not_valid determines if the friendnumber passed is valid in the Messenger object\nstatic uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber)\n{\n    if ((unsigned int)friendnumber < m->numfriends) {\n        if (m->friendlist[friendnumber].status != 0) {\n            return 0;\n        }\n    }\n\n    return 1;\n}\n\n/* Set the size of the friend list to numfriends.\n *\n *  return -1 if realloc fails.\n */\nint realloc_friendlist(Messenger *m, uint32_t num)\n{\n    if (num == 0) {\n        free(m->friendlist);\n        m->friendlist = NULL;\n        return 0;\n    }\n\n    Friend *newfriendlist = realloc(m->friendlist, num * sizeof(Friend));\n\n    if (newfriendlist == NULL)\n        return -1;\n\n    m->friendlist = newfriendlist;\n    return 0;\n}\n\n/*  return the friend id associated to that public key.\n *  return -1 if no such friend.\n */\nint32_t getfriend_id(const Messenger *m, const uint8_t *real_pk)\n{\n    uint32_t i;\n\n    for (i = 0; i < m->numfriends; ++i) {\n        if (m->friendlist[i].status > 0)\n            if (id_equal(real_pk, m->friendlist[i].real_pk))\n                return i;\n    }\n\n    return -1;\n}\n\n/* Copies the public key associated to that friend id into real_pk buffer.\n * Make sure that real_pk is of size crypto_box_PUBLICKEYBYTES.\n *\n *  return 0 if success.\n *  return -1 if failure.\n */\nint get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    memcpy(real_pk, m->friendlist[friendnumber].real_pk, crypto_box_PUBLICKEYBYTES);\n    return 0;\n}\n\n/*  return friend connection id on success.\n *  return -1 if failure.\n */\nint getfriendcon_id(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    return m->friendlist[friendnumber].friendcon_id;\n}\n\n/*\n *  return a uint16_t that represents the checksum of address of length len.\n */\nstatic uint16_t address_checksum(const uint8_t *address, uint32_t len)\n{\n    uint8_t checksum[2] = {0};\n    uint16_t check;\n    uint32_t i;\n\n    for (i = 0; i < len; ++i)\n        checksum[i % 2] ^= address[i];\n\n    memcpy(&check, checksum, sizeof(check));\n    return check;\n}\n\n/* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]\n *\n *  return FRIEND_ADDRESS_SIZE byte address to give to others.\n */\nvoid getaddress(const Messenger *m, uint8_t *address)\n{\n    id_copy(address, m->net_crypto->self_public_key);\n    uint32_t nospam = get_nospam(&(m->fr));\n    memcpy(address + crypto_box_PUBLICKEYBYTES, &nospam, sizeof(nospam));\n    uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));\n    memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(nospam), &checksum, sizeof(checksum));\n}\n\nstatic int send_online_packet(Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return 0;\n\n    uint8_t packet = PACKET_ID_ONLINE;\n    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                             m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1;\n}\n\nstatic int send_offline_packet(Messenger *m, int friendcon_id)\n{\n    uint8_t packet = PACKET_ID_OFFLINE;\n    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet,\n                             sizeof(packet), 0) != -1;\n}\n\nstatic int handle_status(void *object, int i, uint8_t status);\nstatic int handle_packet(void *object, int i, uint8_t *temp, uint16_t len);\nstatic int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length);\n\nstatic int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t status)\n{\n    /* Resize the friend list if necessary. */\n    if (realloc_friendlist(m, m->numfriends + 1) != 0)\n        return FAERR_NOMEM;\n\n    memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend));\n\n    int friendcon_id = new_friend_connection(m->fr_c, real_pk);\n\n    if (friendcon_id == -1)\n        return FAERR_NOMEM;\n\n    uint32_t i;\n\n    for (i = 0; i <= m->numfriends; ++i) {\n        if (m->friendlist[i].status == NOFRIEND) {\n            m->friendlist[i].status = status;\n            m->friendlist[i].friendcon_id = friendcon_id;\n            m->friendlist[i].friendrequest_lastsent = 0;\n            id_copy(m->friendlist[i].real_pk, real_pk);\n            m->friendlist[i].statusmessage_length = 0;\n            m->friendlist[i].userstatus = USERSTATUS_NONE;\n            m->friendlist[i].is_typing = 0;\n            m->friendlist[i].message_id = 0;\n            friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &handle_status, &handle_packet,\n                                        &handle_custom_lossy_packet, m, i);\n\n            if (m->numfriends == i)\n                ++m->numfriends;\n\n            if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {\n                send_online_packet(m, i);\n            }\n\n            return i;\n        }\n    }\n\n    return FAERR_NOMEM;\n}\n\n/*\n * Add a friend.\n * Set the data that will be sent along with friend request.\n * Address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes.\n * data is the data and length is the length.\n *\n *  return the friend number if success.\n *  return FA_TOOLONG if message length is too long.\n *  return FAERR_NOMESSAGE if no message (message length must be >= 1 byte).\n *  return FAERR_OWNKEY if user's own key.\n *  return FAERR_ALREADYSENT if friend request already sent or already a friend.\n *  return FAERR_BADCHECKSUM if bad checksum in address.\n *  return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different.\n *  (the nospam for that friend was set to the new one).\n *  return FAERR_NOMEM if increasing the friend list size fails.\n */\nint32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length)\n{\n    if (length > MAX_FRIEND_REQUEST_DATA_SIZE)\n        return FAERR_TOOLONG;\n\n    uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n    id_copy(real_pk, address);\n\n    if (!public_key_valid(real_pk))\n        return FAERR_BADCHECKSUM;\n\n    uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));\n    memcpy(&check, address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), sizeof(check));\n\n    if (check != checksum)\n        return FAERR_BADCHECKSUM;\n\n    if (length < 1)\n        return FAERR_NOMESSAGE;\n\n    if (id_equal(real_pk, m->net_crypto->self_public_key))\n        return FAERR_OWNKEY;\n\n    int32_t friend_id = getfriend_id(m, real_pk);\n\n    if (friend_id != -1) {\n        if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED)\n            return FAERR_ALREADYSENT;\n\n        uint32_t nospam;\n        memcpy(&nospam, address + crypto_box_PUBLICKEYBYTES, sizeof(nospam));\n\n        if (m->friendlist[friend_id].friendrequest_nospam == nospam)\n            return FAERR_ALREADYSENT;\n\n        m->friendlist[friend_id].friendrequest_nospam = nospam;\n        return FAERR_SETNEWNOSPAM;\n    }\n\n    int32_t ret = init_new_friend(m, real_pk, FRIEND_ADDED);\n\n    if (ret < 0) {\n        return ret;\n    }\n\n    m->friendlist[ret].friendrequest_timeout = FRIENDREQUEST_TIMEOUT;\n    memcpy(m->friendlist[ret].info, data, length);\n    m->friendlist[ret].info_size = length;\n    memcpy(&(m->friendlist[ret].friendrequest_nospam), address + crypto_box_PUBLICKEYBYTES, sizeof(uint32_t));\n\n    return ret;\n}\n\nint32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk)\n{\n    if (getfriend_id(m, real_pk) != -1)\n        return FAERR_ALREADYSENT;\n\n    if (!public_key_valid(real_pk))\n        return FAERR_BADCHECKSUM;\n\n    if (id_equal(real_pk, m->net_crypto->self_public_key))\n        return FAERR_OWNKEY;\n\n    return init_new_friend(m, real_pk, FRIEND_CONFIRMED);\n}\n\nstatic int clear_receipts(Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    struct Receipts *receipts = m->friendlist[friendnumber].receipts_start;\n\n    while (receipts) {\n        struct Receipts *temp_r = receipts->next;\n        free(receipts);\n        receipts = temp_r;\n    }\n\n    m->friendlist[friendnumber].receipts_start = NULL;\n    m->friendlist[friendnumber].receipts_end = NULL;\n    return 0;\n}\n\nstatic int add_receipt(Messenger *m, int32_t friendnumber, uint32_t packet_num, uint32_t msg_id)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    struct Receipts *new = calloc(1, sizeof(struct Receipts));\n\n    if (!new)\n        return -1;\n\n    new->packet_num = packet_num;\n    new->msg_id = msg_id;\n\n    if (!m->friendlist[friendnumber].receipts_start) {\n        m->friendlist[friendnumber].receipts_start = new;\n    } else {\n        m->friendlist[friendnumber].receipts_end->next = new;\n    }\n\n    m->friendlist[friendnumber].receipts_end = new;\n    new->next = NULL;\n    return 0;\n}\n/*\n * return -1 on failure.\n * return 0 if packet was received.\n */\nstatic int friend_received_packet(const Messenger *m, int32_t friendnumber, uint32_t number)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                                m->friendlist[friendnumber].friendcon_id), number);\n}\n\nstatic int do_receipts(Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    struct Receipts *receipts = m->friendlist[friendnumber].receipts_start;\n\n    while (receipts) {\n        struct Receipts *temp_r = receipts->next;\n\n        if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1)\n            break;\n\n        if (m->read_receipt)\n            (*m->read_receipt)(m, friendnumber, receipts->msg_id, m->read_receipt_userdata);\n\n        free(receipts);\n        m->friendlist[friendnumber].receipts_start = temp_r;\n        receipts = temp_r;\n    }\n\n    if (!m->friendlist[friendnumber].receipts_start)\n        m->friendlist[friendnumber].receipts_end = NULL;\n\n    return 0;\n}\n\n/* Remove a friend.\n *\n *  return 0 if success.\n *  return -1 if failure.\n */\nint m_delfriend(Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friend_connectionstatuschange_internal)\n        m->friend_connectionstatuschange_internal(m, friendnumber, 0, m->friend_connectionstatuschange_internal_userdata);\n\n    clear_receipts(m, friendnumber);\n    remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk);\n    friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0);\n\n    if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {\n        send_offline_packet(m, m->friendlist[friendnumber].friendcon_id);\n    }\n\n    kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id);\n    memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend));\n    uint32_t i;\n\n    for (i = m->numfriends; i != 0; --i) {\n        if (m->friendlist[i - 1].status != NOFRIEND)\n            break;\n    }\n\n    m->numfriends = i;\n\n    if (realloc_friendlist(m, m->numfriends) != 0)\n        return FAERR_NOMEM;\n\n    return 0;\n}\n\nint m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friendlist[friendnumber].status == FRIEND_ONLINE) {\n        _Bool direct_connected = 0;\n        unsigned int num_online_relays = 0;\n        crypto_connection_status(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                                 m->friendlist[friendnumber].friendcon_id), &direct_connected, &num_online_relays);\n\n        if (direct_connected) {\n            return CONNECTION_UDP;\n        } else {\n            if (num_online_relays) {\n                return CONNECTION_TCP;\n            } else {\n                return CONNECTION_UNKNOWN;\n            }\n        }\n    } else {\n        return CONNECTION_NONE;\n    }\n}\n\nint m_friend_exists(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return 0;\n\n    return 1;\n}\n\n/* Send a message of type.\n *\n * return -1 if friend not valid.\n * return -2 if too large.\n * return -3 if friend not online.\n * return -4 if send failed (because queue is full).\n * return -5 if bad type.\n * return 0 if success.\n */\nint m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,\n                           uint32_t *message_id)\n{\n    if (type > MESSAGE_ACTION)\n        return -5;\n\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (length >= MAX_CRYPTO_DATA_SIZE)\n        return -2;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -3;\n\n    uint8_t packet[length + 1];\n    packet[0] = type + PACKET_ID_MESSAGE;\n\n    if (length != 0)\n        memcpy(packet + 1, message, length);\n\n    int64_t packet_num = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                                           m->friendlist[friendnumber].friendcon_id), packet, length + 1, 0);\n\n    if (packet_num == -1)\n        return -4;\n\n    uint32_t msg_id = ++m->friendlist[friendnumber].message_id;\n\n    add_receipt(m, friendnumber, packet_num, msg_id);\n\n    if (message_id)\n        *message_id = msg_id;\n\n    return 0;\n}\n\n/* Send a name packet to friendnumber.\n * length is the length with the NULL terminator.\n */\nstatic int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)\n{\n    if (length > MAX_NAME_LENGTH)\n        return 0;\n\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, 0);\n}\n\n/* Set the name and name_length of a friend.\n *\n *  return 0 if success.\n *  return -1 if failure.\n */\nint setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (length > MAX_NAME_LENGTH || length == 0)\n        return -1;\n\n    m->friendlist[friendnumber].name_length = length;\n    memcpy(m->friendlist[friendnumber].name, name, length);\n    return 0;\n}\n\n/* Set our nickname\n * name must be a string of maximum MAX_NAME_LENGTH length.\n * length must be at least 1 byte.\n * length is the length of name with the NULL terminator.\n *\n *  return 0 if success.\n *  return -1 if failure.\n */\nint setname(Messenger *m, const uint8_t *name, uint16_t length)\n{\n    if (length > MAX_NAME_LENGTH)\n        return -1;\n\n    if (m->name_length == length && (length == 0 || memcmp(name, m->name, length) == 0))\n        return 0;\n\n    if (length)\n        memcpy(m->name, name, length);\n\n    m->name_length = length;\n    uint32_t i;\n\n    for (i = 0; i < m->numfriends; ++i)\n        m->friendlist[i].name_sent = 0;\n\n    return 0;\n}\n\n/* Get our nickname and put it in name.\n * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.\n *\n *  return the length of the name.\n */\nuint16_t getself_name(const Messenger *m, uint8_t *name)\n{\n    if (name == NULL) {\n        return 0;\n    }\n\n    memcpy(name, m->name, m->name_length);\n\n    return m->name_length;\n}\n\n/* Get name of friendnumber and put it in name.\n * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.\n *\n *  return length of name if success.\n *  return -1 if failure.\n */\nint getname(const Messenger *m, int32_t friendnumber, uint8_t *name)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    memcpy(name, m->friendlist[friendnumber].name, m->friendlist[friendnumber].name_length);\n    return m->friendlist[friendnumber].name_length;\n}\n\nint m_get_name_size(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    return m->friendlist[friendnumber].name_length;\n}\n\nint m_get_self_name_size(const Messenger *m)\n{\n    return m->name_length;\n}\n\nint m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length)\n{\n    if (length > MAX_STATUSMESSAGE_LENGTH)\n        return -1;\n\n    if (m->statusmessage_length == length && (length == 0 || memcmp(m->statusmessage, status, length) == 0))\n        return 0;\n\n    if (length)\n        memcpy(m->statusmessage, status, length);\n\n    m->statusmessage_length = length;\n\n    uint32_t i;\n\n    for (i = 0; i < m->numfriends; ++i)\n        m->friendlist[i].statusmessage_sent = 0;\n\n    return 0;\n}\n\nint m_set_userstatus(Messenger *m, uint8_t status)\n{\n    if (status >= USERSTATUS_INVALID)\n        return -1;\n\n    if (m->userstatus == status)\n        return 0;\n\n    m->userstatus = status;\n    uint32_t i;\n\n    for (i = 0; i < m->numfriends; ++i)\n        m->friendlist[i].userstatus_sent = 0;\n\n    return 0;\n}\n\n/* return the size of friendnumber's user status.\n * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.\n */\nint m_get_statusmessage_size(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    return m->friendlist[friendnumber].statusmessage_length;\n}\n\n/*  Copy the user status of friendnumber into buf, truncating if needed to maxlen\n *  bytes, use m_get_statusmessage_size to find out how much you need to allocate.\n */\nint m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    int msglen = MIN(maxlen, m->friendlist[friendnumber].statusmessage_length);\n\n    memcpy(buf, m->friendlist[friendnumber].statusmessage, msglen);\n    memset(buf + msglen, 0, maxlen - msglen);\n    return msglen;\n}\n\n/* return the size of friendnumber's user status.\n * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH.\n */\nint m_get_self_statusmessage_size(const Messenger *m)\n{\n    return m->statusmessage_length;\n}\n\nint m_copy_self_statusmessage(const Messenger *m, uint8_t *buf)\n{\n    memcpy(buf, m->statusmessage, m->statusmessage_length);\n    return m->statusmessage_length;\n}\n\nuint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return USERSTATUS_INVALID;\n\n    uint8_t status = m->friendlist[friendnumber].userstatus;\n\n    if (status >= USERSTATUS_INVALID) {\n        status = USERSTATUS_NONE;\n    }\n\n    return status;\n}\n\nuint8_t m_get_self_userstatus(const Messenger *m)\n{\n    return m->userstatus;\n}\n\nuint64_t m_get_last_online(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return UINT64_MAX;\n\n    return m->friendlist[friendnumber].last_seen_time;\n}\n\nint m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing)\n\n{\n    if (is_typing != 0 && is_typing != 1)\n        return -1;\n\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friendlist[friendnumber].user_istyping == is_typing)\n        return 0;\n\n    m->friendlist[friendnumber].user_istyping = is_typing;\n    m->friendlist[friendnumber].user_istyping_sent = 0;\n\n    return 0;\n}\n\nint m_get_istyping(const Messenger *m, int32_t friendnumber)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    return m->friendlist[friendnumber].is_typing;\n}\n\nstatic int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length)\n{\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, 0);\n}\n\nstatic int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)\n{\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), 0);\n}\n\nstatic int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing)\n{\n    uint8_t typing = is_typing;\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0);\n}\n\nstatic int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (length > MAX_STATUSMESSAGE_LENGTH)\n        return -1;\n\n    if (length)\n        memcpy(m->friendlist[friendnumber].statusmessage, status, length);\n\n    m->friendlist[friendnumber].statusmessage_length = length;\n    return 0;\n}\n\nstatic void set_friend_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status)\n{\n    m->friendlist[friendnumber].userstatus = status;\n}\n\nstatic void set_friend_typing(const Messenger *m, int32_t friendnumber, uint8_t is_typing)\n{\n    m->friendlist[friendnumber].is_typing = is_typing;\n}\n\n/* Set the function that will be executed when a friend request is received. */\nvoid m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t,\n                              void *), void *userdata)\n{\n    void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, size_t, void *) = (void *)function;\n    callback_friendrequest(&(m->fr), handle_friendrequest, m, userdata);\n}\n\n/* Set the function that will be executed when a message from a friend is received. */\nvoid m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, const uint8_t *,\n                              size_t, void *), void *userdata)\n{\n    m->friend_message = function;\n    m->friend_message_userdata = userdata;\n}\n\nvoid m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *),\n                           void *userdata)\n{\n    m->friend_namechange = function;\n    m->friend_namechange_userdata = userdata;\n}\n\nvoid m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *),\n                              void *userdata)\n{\n    m->friend_statusmessagechange = function;\n    m->friend_statusmessagechange_userdata = userdata;\n}\n\nvoid m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *), void *userdata)\n{\n    m->friend_userstatuschange = function;\n    m->friend_userstatuschange_userdata = userdata;\n}\n\nvoid m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, _Bool, void *), void *userdata)\n{\n    m->friend_typingchange = function;\n    m->friend_typingchange_userdata = userdata;\n}\n\nvoid m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *), void *userdata)\n{\n    m->read_receipt = function;\n    m->read_receipt_userdata = userdata;\n}\n\nvoid m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *),\n                                 void *userdata)\n{\n    m->friend_connectionstatuschange = function;\n    m->friend_connectionstatuschange_userdata = userdata;\n}\n\nvoid m_callback_core_connection(Messenger *m, void (*function)(Messenger *m, unsigned int, void *), void *userdata)\n{\n    m->core_connection_change = function;\n    m->core_connection_change_userdata = userdata;\n}\n\nvoid m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *),\n        void *userdata)\n{\n    m->friend_connectionstatuschange_internal = function;\n    m->friend_connectionstatuschange_internal_userdata = userdata;\n}\n\nstatic void check_friend_tcp_udp(Messenger *m, int32_t friendnumber)\n{\n    int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp;\n\n    int ret = m_get_friend_connectionstatus(m, friendnumber);\n\n    if (ret == -1)\n        return;\n\n    if (ret == CONNECTION_UNKNOWN) {\n        if (last_connection_udp_tcp == CONNECTION_UDP) {\n            return;\n        } else {\n            ret = CONNECTION_TCP;\n        }\n    }\n\n    if (last_connection_udp_tcp != ret) {\n        if (m->friend_connectionstatuschange)\n            m->friend_connectionstatuschange(m, friendnumber, ret, m->friend_connectionstatuschange_userdata);\n    }\n\n    m->friendlist[friendnumber].last_connection_udp_tcp = ret;\n}\n\nstatic void break_files(const Messenger *m, int32_t friendnumber);\nstatic void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status)\n{\n    if (status == NOFRIEND)\n        return;\n\n    const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE;\n    const uint8_t is_online = status == FRIEND_ONLINE;\n\n    if (is_online != was_online) {\n        if (was_online) {\n            break_files(m, friendnumber);\n            clear_receipts(m, friendnumber);\n        } else {\n            m->friendlist[friendnumber].name_sent = 0;\n            m->friendlist[friendnumber].userstatus_sent = 0;\n            m->friendlist[friendnumber].statusmessage_sent = 0;\n            m->friendlist[friendnumber].user_istyping_sent = 0;\n        }\n\n        m->friendlist[friendnumber].status = status;\n\n        check_friend_tcp_udp(m, friendnumber);\n\n        if (m->friend_connectionstatuschange_internal)\n            m->friend_connectionstatuschange_internal(m, friendnumber, is_online,\n                    m->friend_connectionstatuschange_internal_userdata);\n    }\n}\n\nvoid set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status)\n{\n    check_friend_connectionstatus(m, friendnumber, status);\n    m->friendlist[friendnumber].status = status;\n}\n\nstatic int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data,\n                                uint32_t length, uint8_t congestion_control)\n{\n    if (friend_not_valid(m, friendnumber))\n        return 0;\n\n    if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return 0;\n\n    uint8_t packet[length + 1];\n    packet[0] = packet_id;\n\n    if (length != 0)\n        memcpy(packet + 1, data, length);\n\n    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                             m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1;\n}\n\n/**********GROUP CHATS************/\n\n\n/* Set the callback for group invites.\n *\n *  Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length)\n */\nvoid m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t))\n{\n    m->group_invite = function;\n}\n\n\n/* Send a group invite packet.\n *\n *  return 1 on success\n *  return 0 on failure\n */\nint send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)\n{\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_GROUPCHAT, data, length, 0);\n}\n\n/****************FILE SENDING*****************/\n\n\n/* Set the callback for file send requests.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint32_t filetype, uint64_t filesize, uint8_t *filename, size_t filename_length, void *userdata)\n */\nvoid callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m,  uint32_t, uint32_t, uint32_t, uint64_t,\n                               const uint8_t *, size_t, void *), void *userdata)\n{\n    m->file_sendrequest = function;\n    m->file_sendrequest_userdata = userdata;\n}\n\n/* Set the callback for file control requests.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata)\n *\n */\nvoid callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *),\n                           void *userdata)\n{\n    m->file_filecontrol = function;\n    m->file_filecontrol_userdata = userdata;\n}\n\n/* Set the callback for file data.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata)\n *\n */\nvoid callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *,\n                        size_t, void *), void *userdata)\n{\n    m->file_filedata = function;\n    m->file_filedata_userdata = userdata;\n}\n\n/* Set the callback for file request chunk.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata)\n *\n */\nvoid callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),\n                            void *userdata)\n{\n    m->file_reqchunk = function;\n    m->file_reqchunk_userdata = userdata;\n}\n\n#define MAX_FILENAME_LENGTH 255\n\n/* Copy the file transfer file id to file_id\n *\n * return 0 on success.\n * return -1 if friend not valid.\n * return -2 if filenumber not valid\n */\nint file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -2;\n\n    uint32_t temp_filenum;\n    uint8_t send_receive, file_number;\n\n    if (filenumber >= (1 << 16)) {\n        send_receive = 1;\n        temp_filenum = (filenumber >> 16) - 1;\n    } else {\n        send_receive = 0;\n        temp_filenum = filenumber;\n    }\n\n    if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES)\n        return -2;\n\n    file_number = temp_filenum;\n\n    struct File_Transfers *ft;\n\n    if (send_receive) {\n        ft = &m->friendlist[friendnumber].file_receiving[file_number];\n    } else {\n        ft = &m->friendlist[friendnumber].file_sending[file_number];\n    }\n\n    if (ft->status == FILESTATUS_NONE)\n        return -2;\n\n    memcpy(file_id, ft->id, FILE_ID_LENGTH);\n    return 0;\n}\n\n/* Send a file send request.\n * Maximum filename length is 255 bytes.\n *  return 1 on success\n *  return 0 on failure\n */\nstatic int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint32_t file_type,\n                            uint64_t filesize, const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return 0;\n\n    if (filename_length > MAX_FILENAME_LENGTH)\n        return 0;\n\n    uint8_t packet[1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH + filename_length];\n    packet[0] = filenumber;\n    file_type = htonl(file_type);\n    memcpy(packet + 1, &file_type, sizeof(file_type));\n    host_to_net((uint8_t *)&filesize, sizeof(filesize));\n    memcpy(packet + 1 + sizeof(file_type), &filesize, sizeof(filesize));\n    memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), file_id, FILE_ID_LENGTH);\n\n    if (filename_length) {\n        memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH, filename, filename_length);\n    }\n\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, sizeof(packet), 0);\n}\n\n/* Send a file send request.\n * Maximum filename length is 255 bytes.\n *  return file number on success\n *  return -1 if friend not found.\n *  return -2 if filename length invalid.\n *  return -3 if no more file sending slots left.\n *  return -4 if could not send packet (friend offline).\n *\n */\nlong int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,\n                        const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (filename_length > MAX_FILENAME_LENGTH)\n        return -2;\n\n    uint32_t i;\n\n    for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {\n        if (m->friendlist[friendnumber].file_sending[i].status == FILESTATUS_NONE)\n            break;\n    }\n\n    if (i == MAX_CONCURRENT_FILE_PIPES)\n        return -3;\n\n    if (file_sendrequest(m, friendnumber, i, file_type, filesize, file_id, filename, filename_length) == 0)\n        return -4;\n\n    struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];\n    ft->status = FILESTATUS_NOT_ACCEPTED;\n    ft->size = filesize;\n    ft->transferred = 0;\n    ft->requested = 0;\n    ft->slots_allocated = 0;\n    ft->paused = FILE_PAUSE_NOT;\n    memcpy(ft->id, file_id, FILE_ID_LENGTH);\n\n    ++m->friendlist[friendnumber].num_sending_files;\n\n    return i;\n}\n\nint send_file_control_packet(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber,\n                             uint8_t control_type, uint8_t *data, uint16_t data_length)\n{\n    if ((unsigned int)(1 + 3 + data_length) > MAX_CRYPTO_DATA_SIZE)\n        return -1;\n\n    uint8_t packet[3 + data_length];\n\n    packet[0] = send_receive;\n    packet[1] = filenumber;\n    packet[2] = control_type;\n\n    if (data_length) {\n        memcpy(packet + 3, data, data_length);\n    }\n\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, sizeof(packet), 0);\n}\n\n/* Send a file control request.\n *\n *  return 0 on success\n *  return -1 if friend not valid.\n *  return -2 if friend not online.\n *  return -3 if file number invalid.\n *  return -4 if file control is bad.\n *  return -5 if file already paused.\n *  return -6 if resume file failed because it was only paused by the other.\n *  return -7 if resume file failed because it wasn't paused.\n *  return -8 if packet failed to send.\n */\nint file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -2;\n\n    uint32_t temp_filenum;\n    uint8_t send_receive, file_number;\n\n    if (filenumber >= (1 << 16)) {\n        send_receive = 1;\n        temp_filenum = (filenumber >> 16) - 1;\n    } else {\n        send_receive = 0;\n        temp_filenum = filenumber;\n    }\n\n    if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES)\n        return -3;\n\n    file_number = temp_filenum;\n\n    struct File_Transfers *ft;\n\n    if (send_receive) {\n        ft = &m->friendlist[friendnumber].file_receiving[file_number];\n    } else {\n        ft = &m->friendlist[friendnumber].file_sending[file_number];\n    }\n\n    if (ft->status == FILESTATUS_NONE)\n        return -3;\n\n    if (control > FILECONTROL_KILL)\n        return -4;\n\n    if (control == FILECONTROL_PAUSE && ((ft->paused & FILE_PAUSE_US) || ft->status != FILESTATUS_TRANSFERRING))\n        return -5;\n\n    if (control == FILECONTROL_ACCEPT) {\n        if (ft->status == FILESTATUS_TRANSFERRING) {\n            if (!(ft->paused & FILE_PAUSE_US)) {\n                if (ft->paused & FILE_PAUSE_OTHER) {\n                    return -6;\n                } else {\n                    return -7;\n                }\n            }\n        } else {\n            if (ft->status != FILESTATUS_NOT_ACCEPTED)\n                return -7;\n\n            if (!send_receive)\n                return -6;\n        }\n    }\n\n    if (send_file_control_packet(m, friendnumber, send_receive, file_number, control, 0, 0)) {\n        if (control == FILECONTROL_KILL) {\n            ft->status = FILESTATUS_NONE;\n\n            if (send_receive == 0) {\n                --m->friendlist[friendnumber].num_sending_files;\n            }\n        } else if (control == FILECONTROL_PAUSE) {\n            ft->paused |= FILE_PAUSE_US;\n        } else if (control == FILECONTROL_ACCEPT) {\n            ft->status = FILESTATUS_TRANSFERRING;\n\n            if (ft->paused & FILE_PAUSE_US) {\n                ft->paused ^=  FILE_PAUSE_US;\n            }\n        }\n    } else {\n        return -8;\n    }\n\n    return 0;\n}\n\n/* Send a seek file control request.\n *\n *  return 0 on success\n *  return -1 if friend not valid.\n *  return -2 if friend not online.\n *  return -3 if file number invalid.\n *  return -4 if not receiving file.\n *  return -5 if file status wrong.\n *  return -6 if position bad.\n *  return -8 if packet failed to send.\n */\nint file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -2;\n\n    uint32_t temp_filenum;\n    uint8_t send_receive, file_number;\n\n    if (filenumber >= (1 << 16)) {\n        send_receive = 1;\n        temp_filenum = (filenumber >> 16) - 1;\n    } else {\n        return -4;\n    }\n\n    if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES)\n        return -3;\n\n    file_number = temp_filenum;\n\n    struct File_Transfers *ft;\n\n    if (send_receive) {\n        ft = &m->friendlist[friendnumber].file_receiving[file_number];\n    } else {\n        ft = &m->friendlist[friendnumber].file_sending[file_number];\n    }\n\n    if (ft->status == FILESTATUS_NONE)\n        return -3;\n\n    if (ft->status != FILESTATUS_NOT_ACCEPTED)\n        return -5;\n\n    if (position >= ft->size) {\n        return -6;\n    }\n\n    uint64_t sending_pos = position;\n    host_to_net((uint8_t *)&sending_pos, sizeof(sending_pos));\n\n    if (send_file_control_packet(m, friendnumber, send_receive, file_number, FILECONTROL_SEEK, (uint8_t *)&sending_pos,\n                                 sizeof(sending_pos))) {\n        ft->transferred = position;\n    } else {\n        return -8;\n    }\n\n    return 0;\n}\n\n/* return packet number on success.\n * return -1 on failure.\n */\nstatic int64_t send_file_data_packet(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data,\n                                     uint16_t length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    uint8_t packet[2 + length];\n    packet[0] = PACKET_ID_FILE_DATA;\n    packet[1] = filenumber;\n\n    if (length) {\n        memcpy(packet + 2, data, length);\n    }\n\n    return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                             m->friendlist[friendnumber].friendcon_id), packet, sizeof(packet), 1);\n}\n\n#define MAX_FILE_DATA_SIZE (MAX_CRYPTO_DATA_SIZE - 2)\n#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 4)\n/* Send file data.\n *\n *  return 0 on success\n *  return -1 if friend not valid.\n *  return -2 if friend not online.\n *  return -3 if filenumber invalid.\n *  return -4 if file transfer not transferring.\n *  return -5 if bad data size.\n *  return -6 if packet queue full.\n *  return -7 if wrong position.\n */\nint file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,\n              uint16_t length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -2;\n\n    if (filenumber >= MAX_CONCURRENT_FILE_PIPES)\n        return -3;\n\n    struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber];\n\n    if (ft->status != FILESTATUS_TRANSFERRING)\n        return -4;\n\n    if (length > MAX_FILE_DATA_SIZE)\n        return -5;\n\n    if (ft->size - ft->transferred < length) {\n        return -5;\n    }\n\n    if (ft->size != UINT64_MAX && length != MAX_FILE_DATA_SIZE && (ft->transferred + length) != ft->size) {\n        return -5;\n    }\n\n    if (position != ft->transferred || (ft->requested <= position && ft->size != 0)) {\n        return -7;\n    }\n\n    /* Prevent file sending from filling up the entire buffer preventing messages from being sent. TODO: remove */\n    if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                                        m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE)\n        return -6;\n\n    int64_t ret = send_file_data_packet(m, friendnumber, filenumber, data, length);\n\n    if (ret != -1) {\n        //TODO record packet ids to check if other received complete file.\n        ft->transferred += length;\n\n        if (ft->slots_allocated) {\n            --ft->slots_allocated;\n        }\n\n        if (length != MAX_FILE_DATA_SIZE || ft->size == ft->transferred) {\n            ft->status = FILESTATUS_FINISHED;\n            ft->last_packet_number = ret;\n        }\n\n        return 0;\n    }\n\n    return -6;\n\n}\n\n/* Give the number of bytes left to be sent/received.\n *\n *  send_receive is 0 if we want the sending files, 1 if we want the receiving.\n *\n *  return number of bytes remaining to be sent/received on success\n *  return 0 on failure\n */\nuint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive)\n{\n    if (friend_not_valid(m, friendnumber))\n        return 0;\n\n    if (send_receive == 0) {\n        if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE)\n            return 0;\n\n        return m->friendlist[friendnumber].file_sending[filenumber].size -\n               m->friendlist[friendnumber].file_sending[filenumber].transferred;\n    } else {\n        if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE)\n            return 0;\n\n        return m->friendlist[friendnumber].file_receiving[filenumber].size -\n               m->friendlist[friendnumber].file_receiving[filenumber].transferred;\n    }\n}\n\nstatic void do_reqchunk_filecb(Messenger *m, int32_t friendnumber)\n{\n    if (!m->friendlist[friendnumber].num_sending_files)\n        return;\n\n    int free_slots = crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                     m->friendlist[friendnumber].friendcon_id));\n\n    if (free_slots < MIN_SLOTS_FREE) {\n        free_slots = 0;\n    } else {\n        free_slots -= MIN_SLOTS_FREE;\n    }\n\n    unsigned int i, num = m->friendlist[friendnumber].num_sending_files;\n\n    for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {\n        struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i];\n\n        if (ft->status != FILESTATUS_NONE) {\n            --num;\n\n            if (ft->status == FILESTATUS_FINISHED) {\n                /* Check if file was entirely sent. */\n                if (friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) {\n                    if (m->file_reqchunk)\n                        (*m->file_reqchunk)(m, friendnumber, i, ft->transferred, 0, m->file_reqchunk_userdata);\n\n                    ft->status = FILESTATUS_NONE;\n                    --m->friendlist[friendnumber].num_sending_files;\n                }\n            }\n\n            /* TODO: if file is too slow, switch to the next. */\n            if (ft->slots_allocated > (unsigned int)free_slots) {\n                free_slots = 0;\n            } else {\n                free_slots -= ft->slots_allocated;\n            }\n        }\n\n        while (ft->status == FILESTATUS_TRANSFERRING && (ft->paused == FILE_PAUSE_NOT)) {\n            if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                                  m->friendlist[friendnumber].friendcon_id))) {\n                free_slots = 0;\n            }\n\n            if (free_slots == 0)\n                break;\n\n            uint16_t length = MAX_FILE_DATA_SIZE;\n\n            if (ft->size == 0) {\n                /* Send 0 data to friend if file is 0 length. */\n                file_data(m, friendnumber, i, 0, 0, 0);\n                break;\n            }\n\n            if (ft->size == ft->requested) {\n                break;\n            }\n\n            if (ft->size - ft->requested < length) {\n                length = ft->size - ft->requested;\n            }\n\n            ++ft->slots_allocated;\n\n            uint64_t position = ft->requested;\n            ft->requested += length;\n\n            if (m->file_reqchunk)\n                (*m->file_reqchunk)(m, friendnumber, i, position, length, m->file_reqchunk_userdata);\n\n            --free_slots;\n\n        }\n\n        if (num == 0)\n            break;\n    }\n}\n\n/* Run this when the friend disconnects.\n *  Kill all current file transfers.\n */\nstatic void break_files(const Messenger *m, int32_t friendnumber)\n{\n    uint32_t i;\n\n    //TODO: Inform the client which file transfers get killed with a callback?\n    for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) {\n        if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE)\n            m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NONE;\n\n        if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE)\n            m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_NONE;\n    }\n}\n\n/* return -1 on failure, 0 on success.\n */\nstatic int handle_filecontrol(Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber,\n                              uint8_t control_type, uint8_t *data, uint16_t length)\n{\n    if (receive_send > 1)\n        return -1;\n\n    if (control_type > FILECONTROL_SEEK)\n        return -1;\n\n    uint32_t real_filenumber = filenumber;\n    struct File_Transfers *ft;\n\n    if (receive_send == 0) {\n        real_filenumber += 1;\n        real_filenumber <<= 16;\n        ft = &m->friendlist[friendnumber].file_receiving[filenumber];\n    } else {\n        ft = &m->friendlist[friendnumber].file_sending[filenumber];\n    }\n\n    if (ft->status == FILESTATUS_NONE) {\n        /* File transfer doesn't exist, tell the other to kill it. */\n        send_file_control_packet(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, 0, 0);\n        return -1;\n    }\n\n    if (control_type == FILECONTROL_ACCEPT) {\n        if (receive_send && ft->status == FILESTATUS_NOT_ACCEPTED) {\n            ft->status = FILESTATUS_TRANSFERRING;\n        } else {\n            if (ft->paused & FILE_PAUSE_OTHER) {\n                ft->paused ^= FILE_PAUSE_OTHER;\n            } else {\n                return -1;\n            }\n        }\n\n        if (m->file_filecontrol)\n            (*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);\n    } else if (control_type == FILECONTROL_PAUSE) {\n        if ((ft->paused & FILE_PAUSE_OTHER) || ft->status != FILESTATUS_TRANSFERRING) {\n            return -1;\n        }\n\n        ft->paused |= FILE_PAUSE_OTHER;\n\n        if (m->file_filecontrol)\n            (*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);\n    } else if (control_type == FILECONTROL_KILL) {\n\n        if (m->file_filecontrol)\n            (*m->file_filecontrol)(m, friendnumber, real_filenumber, control_type, m->file_filecontrol_userdata);\n\n        ft->status = FILESTATUS_NONE;\n\n        if (receive_send) {\n            --m->friendlist[friendnumber].num_sending_files;\n        }\n\n    } else if (control_type == FILECONTROL_SEEK) {\n        uint64_t position;\n\n        if (length != sizeof(position)) {\n            return -1;\n        }\n\n        /* seek can only be sent by the receiver to seek before resuming broken transfers. */\n        if (ft->status != FILESTATUS_NOT_ACCEPTED || !receive_send) {\n            return -1;\n        }\n\n        memcpy(&position, data, sizeof(position));\n        net_to_host((uint8_t *) &position, sizeof(position));\n\n        if (position >= ft->size) {\n            return -1;\n        }\n\n        ft->transferred = ft->requested = position;\n    } else {\n        return -1;\n    }\n\n    return 0;\n}\n\n/**************************************/\n\n/* Set the callback for msi packets.\n *\n *  Function(Messenger *m, int friendnumber, uint8_t *data, uint16_t length, void *userdata)\n */\nvoid m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *),\n                           void *userdata)\n{\n    m->msi_packet = function;\n    m->msi_packet_userdata = userdata;\n}\n\n/* Send an msi packet.\n *\n *  return 1 on success\n *  return 0 on failure\n */\nint m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length)\n{\n    return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, 0);\n}\n\nstatic int handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length)\n{\n    Messenger *m = object;\n\n    if (friend_not_valid(m, friend_num))\n        return 1;\n\n    if (packet[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) {\n        if (m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_LOSSY_AV_RESERVED].function)\n            return m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_LOSSY_AV_RESERVED].function(\n                       m, friend_num, packet, length, m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] %\n                               PACKET_LOSSY_AV_RESERVED].object);\n\n        return 1;\n    }\n\n    if (m->lossy_packethandler)\n        m->lossy_packethandler(m, friend_num, packet, length, m->lossy_packethandler_userdata);\n\n    return 1;\n}\n\nvoid custom_lossy_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m,\n        uint32_t friendnumber, const uint8_t *data, size_t len, void *object), void *object)\n{\n    m->lossy_packethandler = packet_handler_callback;\n    m->lossy_packethandler_userdata = object;\n}\n\nint m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, int (*packet_handler_callback)(Messenger *m,\n                          uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object), void *object)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (byte < PACKET_ID_LOSSY_RANGE_START)\n        return -1;\n\n    if (byte >= (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED))\n        return -1;\n\n    m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_LOSSY_AV_RESERVED].function =\n        packet_handler_callback;\n    m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_LOSSY_AV_RESERVED].object = object;\n    return 0;\n}\n\n\nint send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE)\n        return -2;\n\n    if (data[0] < PACKET_ID_LOSSY_RANGE_START)\n        return -3;\n\n    if (data[0] >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE))\n        return -3;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -4;\n\n    if (send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                               m->friendlist[friendnumber].friendcon_id), data, length) == -1) {\n        return -5;\n    } else {\n        return 0;\n    }\n}\n\nstatic int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length)\n{\n    Messenger *m = object;\n\n    if (friend_not_valid(m, friend_num))\n        return -1;\n\n    if (packet[0] < PACKET_ID_LOSSLESS_RANGE_START)\n        return -1;\n\n    if (packet[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE))\n        return -1;\n\n    if (m->lossless_packethandler)\n        m->lossless_packethandler(m, friend_num, packet, length, m->lossless_packethandler_userdata);\n\n    return 1;\n}\n\nvoid custom_lossless_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m,\n        uint32_t friendnumber, const uint8_t *data, size_t len, void *object), void *object)\n{\n    m->lossless_packethandler = packet_handler_callback;\n    m->lossless_packethandler_userdata = object;\n}\n\nint send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length)\n{\n    if (friend_not_valid(m, friendnumber))\n        return -1;\n\n    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE)\n        return -2;\n\n    if (data[0] < PACKET_ID_LOSSLESS_RANGE_START)\n        return -3;\n\n    if (data[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE))\n        return -3;\n\n    if (m->friendlist[friendnumber].status != FRIEND_ONLINE)\n        return -4;\n\n    if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c,\n                          m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) {\n        return -5;\n    } else {\n        return 0;\n    }\n}\n\n/* Function to filter out some friend requests*/\nstatic int friend_already_added(const uint8_t *real_pk, void *data)\n{\n    const Messenger *m = data;\n\n    if (getfriend_id(m, real_pk) == -1)\n        return 0;\n\n    return -1;\n}\n\n/* Run this at startup. */\nMessenger *new_messenger(Messenger_Options *options, unsigned int *error)\n{\n    Messenger *m = calloc(1, sizeof(Messenger));\n\n    if (error)\n        *error = MESSENGER_ERROR_OTHER;\n\n    if ( ! m )\n        return NULL;\n\n    unsigned int net_err = 0;\n\n    if (options->udp_disabled) {\n        /* this is the easiest way to completely disable UDP without changing too much code. */\n        m->net = calloc(1, sizeof(Networking_Core));\n    } else {\n        IP ip;\n        ip_init(&ip, options->ipv6enabled);\n        m->net = new_networking_ex(ip, options->port_range[0], options->port_range[1], &net_err);\n    }\n\n    if (m->net == NULL) {\n        free(m);\n\n        if (error && net_err == 1) {\n            *error = MESSENGER_ERROR_PORT;\n        }\n\n        return NULL;\n    }\n\n    m->dht = new_DHT(m->net);\n\n    if (m->dht == NULL) {\n        kill_networking(m->net);\n        free(m);\n        return NULL;\n    }\n\n    m->net_crypto = new_net_crypto(m->dht, &options->proxy_info);\n\n    if (m->net_crypto == NULL) {\n        kill_networking(m->net);\n        kill_DHT(m->dht);\n        free(m);\n        return NULL;\n    }\n\n    m->onion = new_onion(m->dht);\n    m->onion_a = new_onion_announce(m->dht);\n    m->onion_c =  new_onion_client(m->net_crypto);\n    m->fr_c = new_friend_connections(m->onion_c);\n\n    if (!(m->onion && m->onion_a && m->onion_c)) {\n        kill_friend_connections(m->fr_c);\n        kill_onion(m->onion);\n        kill_onion_announce(m->onion_a);\n        kill_onion_client(m->onion_c);\n        kill_net_crypto(m->net_crypto);\n        kill_DHT(m->dht);\n        kill_networking(m->net);\n        free(m);\n        return NULL;\n    }\n\n    if (options->tcp_server_port) {\n        m->tcp_server = new_TCP_server(options->ipv6enabled, 1, &options->tcp_server_port, m->dht->self_secret_key, m->onion);\n\n        if (m->tcp_server == NULL) {\n            kill_friend_connections(m->fr_c);\n            kill_onion(m->onion);\n            kill_onion_announce(m->onion_a);\n            kill_onion_client(m->onion_c);\n            kill_net_crypto(m->net_crypto);\n            kill_DHT(m->dht);\n            kill_networking(m->net);\n            free(m);\n\n            if (error)\n                *error = MESSENGER_ERROR_TCP_SERVER;\n\n            return NULL;\n        }\n    }\n\n    m->options = *options;\n    friendreq_init(&(m->fr), m->fr_c);\n    set_nospam(&(m->fr), random_int());\n    set_filter_function(&(m->fr), &friend_already_added, m);\n\n    if (error)\n        *error = MESSENGER_ERROR_NONE;\n\n    return m;\n}\n\n/* Run this before closing shop. */\nvoid kill_messenger(Messenger *m)\n{\n    if (!m)\n        return;\n\n    uint32_t i;\n\n    if (m->tcp_server) {\n        kill_TCP_server(m->tcp_server);\n    }\n\n    kill_friend_connections(m->fr_c);\n    kill_onion(m->onion);\n    kill_onion_announce(m->onion_a);\n    kill_onion_client(m->onion_c);\n    kill_net_crypto(m->net_crypto);\n    kill_DHT(m->dht);\n    kill_networking(m->net);\n\n    for (i = 0; i < m->numfriends; ++i) {\n        clear_receipts(m, i);\n    }\n\n    free(m->friendlist);\n    free(m);\n}\n\n/* Check for and handle a timed-out friend request. If the request has\n * timed-out then the friend status is set back to FRIEND_ADDED.\n *   i: friendlist index of the timed-out friend\n *   t: time\n */\nstatic void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t)\n{\n    Friend *f = &m->friendlist[i];\n\n    if (f->friendrequest_lastsent + f->friendrequest_timeout < t) {\n        set_friend_status(m, i, FRIEND_ADDED);\n        /* Double the default timeout every time if friendrequest is assumed\n         * to have been sent unsuccessfully.\n         */\n        f->friendrequest_timeout *= 2;\n    }\n}\n\nstatic int handle_status(void *object, int i, uint8_t status)\n{\n    Messenger *m = object;\n\n    if (status) { /* Went online. */\n        send_online_packet(m, i);\n    } else { /* Went offline. */\n        if (m->friendlist[i].status == FRIEND_ONLINE) {\n            set_friend_status(m, i, FRIEND_CONFIRMED);\n        }\n    }\n\n    return 0;\n}\n\nstatic int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)\n{\n    if (len == 0)\n        return -1;\n\n    Messenger *m = object;\n    uint8_t packet_id = temp[0];\n    uint8_t *data = temp + 1;\n    uint32_t data_length = len - 1;\n\n    if (m->friendlist[i].status != FRIEND_ONLINE) {\n        if (packet_id == PACKET_ID_ONLINE && len == 1) {\n            set_friend_status(m, i, FRIEND_ONLINE);\n            send_online_packet(m, i);\n        } else {\n            return -1;\n        }\n    }\n\n    switch (packet_id) {\n        case PACKET_ID_OFFLINE: {\n            if (data_length != 0)\n                break;\n\n            set_friend_status(m, i, FRIEND_CONFIRMED);\n            break;\n        }\n\n        case PACKET_ID_NICKNAME: {\n            if (data_length > MAX_NAME_LENGTH)\n                break;\n\n            /* Make sure the NULL terminator is present. */\n            uint8_t data_terminated[data_length + 1];\n            memcpy(data_terminated, data, data_length);\n            data_terminated[data_length] = 0;\n\n            /* inform of namechange before we overwrite the old name */\n            if (m->friend_namechange)\n                m->friend_namechange(m, i, data_terminated, data_length, m->friend_namechange_userdata);\n\n            memcpy(m->friendlist[i].name, data_terminated, data_length);\n            m->friendlist[i].name_length = data_length;\n\n            break;\n        }\n\n        case PACKET_ID_STATUSMESSAGE: {\n            if (data_length > MAX_STATUSMESSAGE_LENGTH)\n                break;\n\n            /* Make sure the NULL terminator is present. */\n            uint8_t data_terminated[data_length + 1];\n            memcpy(data_terminated, data, data_length);\n            data_terminated[data_length] = 0;\n\n            if (m->friend_statusmessagechange)\n                m->friend_statusmessagechange(m, i, data_terminated, data_length,\n                                              m->friend_statusmessagechange_userdata);\n\n            set_friend_statusmessage(m, i, data_terminated, data_length);\n            break;\n        }\n\n        case PACKET_ID_USERSTATUS: {\n            if (data_length != 1)\n                break;\n\n            USERSTATUS status = data[0];\n\n            if (status >= USERSTATUS_INVALID)\n                break;\n\n            if (m->friend_userstatuschange)\n                m->friend_userstatuschange(m, i, status, m->friend_userstatuschange_userdata);\n\n            set_friend_userstatus(m, i, status);\n            break;\n        }\n\n        case PACKET_ID_TYPING: {\n            if (data_length != 1)\n                break;\n\n            _Bool typing = !!data[0];\n\n            set_friend_typing(m, i, typing);\n\n            if (m->friend_typingchange)\n                m->friend_typingchange(m, i, typing, m->friend_typingchange_userdata);\n\n            break;\n        }\n\n        case PACKET_ID_MESSAGE:\n        case PACKET_ID_ACTION: {\n            if (data_length == 0)\n                break;\n\n            const uint8_t *message = data;\n            uint16_t message_length = data_length;\n\n            /* Make sure the NULL terminator is present. */\n            uint8_t message_terminated[message_length + 1];\n            memcpy(message_terminated, message, message_length);\n            message_terminated[message_length] = 0;\n            uint8_t type = packet_id - PACKET_ID_MESSAGE;\n\n            if (m->friend_message)\n                (*m->friend_message)(m, i, type, message_terminated, message_length, m->friend_message_userdata);\n\n            break;\n        }\n\n        case PACKET_ID_INVITE_GROUPCHAT: {\n            if (data_length == 0)\n                break;\n\n            if (m->group_invite)\n                (*m->group_invite)(m, i, data, data_length);\n\n            break;\n        }\n\n        case PACKET_ID_FILE_SENDREQUEST: {\n            const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t) + FILE_ID_LENGTH;\n\n            if (data_length < head_length)\n                break;\n\n            uint8_t filenumber = data[0];\n\n            if (filenumber >= MAX_CONCURRENT_FILE_PIPES)\n                break;\n\n            uint64_t filesize;\n            uint32_t file_type;\n            uint16_t filename_length = data_length - head_length;\n\n            if (filename_length > MAX_FILENAME_LENGTH)\n                break;\n\n            memcpy(&file_type, data + 1, sizeof(file_type));\n            file_type = ntohl(file_type);\n\n            memcpy(&filesize, data + 1 + sizeof(uint32_t), sizeof(filesize));\n            net_to_host((uint8_t *) &filesize, sizeof(filesize));\n            struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];\n\n            if (ft->status != FILESTATUS_NONE)\n                break;\n\n            ft->status = FILESTATUS_NOT_ACCEPTED;\n            ft->size = filesize;\n            ft->transferred = 0;\n            ft->paused = FILE_PAUSE_NOT;\n            memcpy(ft->id, data + 1 + sizeof(uint32_t) + sizeof(uint64_t), FILE_ID_LENGTH);\n\n            uint8_t filename_terminated[filename_length + 1];\n            uint8_t *filename = NULL;\n\n            if (filename_length) {\n                /* Force NULL terminate file name. */\n                memcpy(filename_terminated, data + head_length, filename_length);\n                filename_terminated[filename_length] = 0;\n                filename = filename_terminated;\n            }\n\n            uint32_t real_filenumber = filenumber;\n            real_filenumber += 1;\n            real_filenumber <<= 16;\n\n            if (m->file_sendrequest)\n                (*m->file_sendrequest)(m, i, real_filenumber, file_type, filesize, filename, filename_length,\n                                       m->file_sendrequest_userdata);\n\n            break;\n        }\n\n        case PACKET_ID_FILE_CONTROL: {\n            if (data_length < 3)\n                break;\n\n            uint8_t send_receive = data[0];\n            uint8_t filenumber = data[1];\n            uint8_t control_type = data[2];\n\n            if (filenumber >= MAX_CONCURRENT_FILE_PIPES)\n                break;\n\n            if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3) == -1)\n                break;\n\n            break;\n        }\n\n        case PACKET_ID_FILE_DATA: {\n            if (data_length < 1)\n                break;\n\n            uint8_t filenumber = data[0];\n\n            if (filenumber >= MAX_CONCURRENT_FILE_PIPES)\n                break;\n\n            struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber];\n\n            if (ft->status != FILESTATUS_TRANSFERRING)\n                break;\n\n            uint64_t position = ft->transferred;\n            uint32_t real_filenumber = filenumber;\n            real_filenumber += 1;\n            real_filenumber <<= 16;\n            uint16_t file_data_length = (data_length - 1);\n            uint8_t *file_data;\n\n            if (file_data_length == 0) {\n                file_data = NULL;\n            } else {\n                file_data = data + 1;\n            }\n\n            /* Prevent more data than the filesize from being passed to clients. */\n            if ((ft->transferred + file_data_length) > ft->size) {\n                file_data_length = ft->size - ft->transferred;\n            }\n\n            if (m->file_filedata)\n                (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, m->file_filedata_userdata);\n\n            ft->transferred += file_data_length;\n\n            if (file_data_length && (ft->transferred >= ft->size || file_data_length != MAX_FILE_DATA_SIZE)) {\n                file_data_length = 0;\n                file_data = NULL;\n                position = ft->transferred;\n\n                /* Full file received. */\n                if (m->file_filedata)\n                    (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, m->file_filedata_userdata);\n            }\n\n            /* Data is zero, filetransfer is over. */\n            if (file_data_length == 0) {\n                ft->status = FILESTATUS_NONE;\n            }\n\n            break;\n        }\n\n        case PACKET_ID_MSI: {\n            if (data_length == 0)\n                break;\n\n            if (m->msi_packet)\n                (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata);\n\n            break;\n        }\n\n        default: {\n            handle_custom_lossless_packet(object, i, temp, len);\n            break;\n        }\n    }\n\n    return 0;\n}\n\nvoid do_friends(Messenger *m)\n{\n    uint32_t i;\n    uint64_t temp_time = unix_time();\n\n    for (i = 0; i < m->numfriends; ++i) {\n        if (m->friendlist[i].status == FRIEND_ADDED) {\n            int fr = send_friend_request_packet(m->fr_c, m->friendlist[i].friendcon_id, m->friendlist[i].friendrequest_nospam,\n                                                m->friendlist[i].info,\n                                                m->friendlist[i].info_size);\n\n            if (fr >= 0) {\n                set_friend_status(m, i, FRIEND_REQUESTED);\n                m->friendlist[i].friendrequest_lastsent = temp_time;\n            }\n        }\n\n        if (m->friendlist[i].status == FRIEND_REQUESTED\n                || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */\n            if (m->friendlist[i].status == FRIEND_REQUESTED) {\n                /* If we didn't connect to friend after successfully sending him a friend request the request is deemed\n                 * unsuccessful so we set the status back to FRIEND_ADDED and try again.\n                 */\n                check_friend_request_timed_out(m, i, temp_time);\n            }\n        }\n\n        if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */\n            if (m->friendlist[i].name_sent == 0) {\n                if (m_sendname(m, i, m->name, m->name_length))\n                    m->friendlist[i].name_sent = 1;\n            }\n\n            if (m->friendlist[i].statusmessage_sent == 0) {\n                if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length))\n                    m->friendlist[i].statusmessage_sent = 1;\n            }\n\n            if (m->friendlist[i].userstatus_sent == 0) {\n                if (send_userstatus(m, i, m->userstatus))\n                    m->friendlist[i].userstatus_sent = 1;\n            }\n\n            if (m->friendlist[i].user_istyping_sent == 0) {\n                if (send_user_istyping(m, i, m->friendlist[i].user_istyping))\n                    m->friendlist[i].user_istyping_sent = 1;\n            }\n\n            check_friend_tcp_udp(m, i);\n            do_receipts(m, i);\n            do_reqchunk_filecb(m, i);\n\n            m->friendlist[i].last_seen_time = (uint64_t) time(NULL);\n        }\n    }\n}\n\nstatic void connection_status_cb(Messenger *m)\n{\n    unsigned int conn_status = onion_connection_status(m->onion_c);\n\n    if (conn_status != m->last_connection_status) {\n        if (m->core_connection_change)\n            (*m->core_connection_change)(m, conn_status, m->core_connection_change_userdata);\n\n        m->last_connection_status = conn_status;\n    }\n}\n\n\n#ifdef TOX_LOGGER\n#define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL\nstatic time_t lastdump = 0;\nstatic char IDString[crypto_box_PUBLICKEYBYTES * 2 + 1];\nstatic char *ID2String(const uint8_t *pk)\n{\n    uint32_t i;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++)\n        sprintf(&IDString[i * 2], \"%02X\", pk[i]);\n\n    IDString[crypto_box_PUBLICKEYBYTES * 2] = 0;\n    return IDString;\n}\n#endif\n\n/* Minimum messenger run interval in ms\n   TODO: A/V */\n#define MIN_RUN_INTERVAL 50\n\n/* Return the time in milliseconds before do_messenger() should be called again\n * for optimal performance.\n *\n * returns time (in ms) before the next do_messenger() needs to be run on success.\n */\nuint32_t messenger_run_interval(const Messenger *m)\n{\n    uint32_t crypto_interval = crypto_run_interval(m->net_crypto);\n\n    if (crypto_interval > MIN_RUN_INTERVAL) {\n        return MIN_RUN_INTERVAL;\n    } else {\n        return crypto_interval;\n    }\n}\n\n/* The main loop that needs to be run at least 20 times per second. */\nvoid do_messenger(Messenger *m)\n{\n    // Add the TCP relays, but only if this is the first time calling do_messenger\n    if (m->has_added_relays == 0) {\n        m->has_added_relays = 1;\n\n        int i;\n\n        for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) {\n            add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key);\n        }\n\n        if (m->tcp_server) {\n            /* Add self tcp server. */\n            IP_Port local_ip_port;\n            local_ip_port.port = m->options.tcp_server_port;\n            local_ip_port.ip.family = AF_INET;\n            local_ip_port.ip.ip4.uint32 = INADDR_LOOPBACK;\n            add_tcp_relay(m->net_crypto, local_ip_port, m->tcp_server->public_key);\n        }\n    }\n\n    unix_time_update();\n\n    if (!m->options.udp_disabled) {\n        networking_poll(m->net);\n        do_DHT(m->dht);\n    }\n\n    if (m->tcp_server) {\n        do_TCP_server(m->tcp_server);\n    }\n\n    do_net_crypto(m->net_crypto);\n    do_onion_client(m->onion_c);\n    do_friend_connections(m->fr_c);\n    do_friends(m);\n    connection_status_cb(m);\n\n#ifdef TOX_LOGGER\n\n    if (unix_time() > lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) {\n\n#ifdef ENABLE_ASSOC_DHT\n        Assoc_status(m->dht->assoc);\n#endif\n\n        lastdump = unix_time();\n        uint32_t client, last_pinged;\n\n        for (client = 0; client < LCLIENT_LIST; client++) {\n            Client_data *cptr = &m->dht->close_clientlist[client];\n            IPPTsPng *assoc = NULL;\n            uint32_t a;\n\n            for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6)\n                if (ip_isset(&assoc->ip_port.ip)) {\n                    last_pinged = lastdump - assoc->last_pinged;\n\n                    if (last_pinged > 999)\n                        last_pinged = 999;\n\n                    LOGGER_TRACE(\"C[%2u] %s:%u [%3u] %s\",\n                                 client, ip_ntoa(&assoc->ip_port.ip), ntohs(assoc->ip_port.port),\n                                 last_pinged, ID2String(cptr->public_key));\n                }\n        }\n\n\n        uint32_t friend, dhtfriend;\n\n        /* dht contains additional \"friends\" (requests) */\n        uint32_t num_dhtfriends = m->dht->num_friends;\n        int32_t m2dht[num_dhtfriends];\n        int32_t dht2m[num_dhtfriends];\n\n        for (friend = 0; friend < num_dhtfriends; friend++) {\n            m2dht[friend] = -1;\n            dht2m[friend] = -1;\n\n            if (friend >= m->numfriends)\n                continue;\n\n            for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++)\n                if (id_equal(m->friendlist[friend].real_pk, m->dht->friends_list[dhtfriend].public_key)) {\n                    m2dht[friend] = dhtfriend;\n                    break;\n                }\n        }\n\n        for (friend = 0; friend < num_dhtfriends; friend++)\n            if (m2dht[friend] >= 0)\n                dht2m[m2dht[friend]] = friend;\n\n        if (m->numfriends != m->dht->num_friends) {\n            LOGGER_TRACE(\"Friend num in DHT %u != friend num in msger %u\\n\", m->dht->num_friends, m->numfriends);\n        }\n\n        Friend *msgfptr;\n        DHT_Friend *dhtfptr;\n\n        for (friend = 0; friend < num_dhtfriends; friend++) {\n            if (dht2m[friend] >= 0)\n                msgfptr = &m->friendlist[dht2m[friend]];\n            else\n                msgfptr = NULL;\n\n            dhtfptr = &m->dht->friends_list[friend];\n\n            if (msgfptr) {\n                LOGGER_TRACE(\"F[%2u:%2u] <%s> %s\",\n                             dht2m[friend], friend, msgfptr->name,\n                             ID2String(msgfptr->real_pk));\n            } else {\n                LOGGER_TRACE(\"F[--:%2u] %s\", friend, ID2String(dhtfptr->public_key));\n            }\n\n            for (client = 0; client < MAX_FRIEND_CLIENTS; client++) {\n                Client_data *cptr = &dhtfptr->client_list[client];\n                IPPTsPng *assoc = NULL;\n                uint32_t a;\n\n                for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6)\n                    if (ip_isset(&assoc->ip_port.ip)) {\n                        last_pinged = lastdump - assoc->last_pinged;\n\n                        if (last_pinged > 999)\n                            last_pinged = 999;\n\n                        LOGGER_TRACE(\"F[%2u] => C[%2u] %s:%u [%3u] %s\",\n                                     friend, client, ip_ntoa(&assoc->ip_port.ip),\n                                     ntohs(assoc->ip_port.port), last_pinged,\n                                     ID2String(cptr->public_key));\n                    }\n            }\n        }\n    }\n\n#endif /* TOX_LOGGER */\n}\n\n/* new messenger format for load/save, more robust and forward compatible */\n\n#define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f\n\n#define MESSENGER_STATE_COOKIE_TYPE      0x01ce\n#define MESSENGER_STATE_TYPE_NOSPAMKEYS    1\n#define MESSENGER_STATE_TYPE_DHT           2\n#define MESSENGER_STATE_TYPE_FRIENDS       3\n#define MESSENGER_STATE_TYPE_NAME          4\n#define MESSENGER_STATE_TYPE_STATUSMESSAGE 5\n#define MESSENGER_STATE_TYPE_STATUS        6\n#define MESSENGER_STATE_TYPE_TCP_RELAY     10\n#define MESSENGER_STATE_TYPE_PATH_NODE     11\n#define MESSENGER_STATE_TYPE_END           255\n\n#define SAVED_FRIEND_REQUEST_SIZE 1024\n#define NUM_SAVED_PATH_NODES 8\nstruct SAVED_FRIEND {\n    uint8_t status;\n    uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n    uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do.\n    uint16_t info_size; // Length of the info.\n    uint8_t name[MAX_NAME_LENGTH];\n    uint16_t name_length;\n    uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];\n    uint16_t statusmessage_length;\n    uint8_t userstatus;\n    uint32_t friendrequest_nospam;\n    uint64_t last_seen_time;\n};\n\nstatic uint32_t saved_friendslist_size(const Messenger *m)\n{\n    return count_friendlist(m) * sizeof(struct SAVED_FRIEND);\n}\n\nstatic uint32_t friends_list_save(const Messenger *m, uint8_t *data)\n{\n    uint32_t i;\n    uint32_t num = 0;\n\n    for (i = 0; i < m->numfriends; i++) {\n        if (m->friendlist[i].status > 0) {\n            struct SAVED_FRIEND temp;\n            memset(&temp, 0, sizeof(struct SAVED_FRIEND));\n            temp.status = m->friendlist[i].status;\n            memcpy(temp.real_pk, m->friendlist[i].real_pk, crypto_box_PUBLICKEYBYTES);\n\n            if (temp.status < 3) {\n                if (m->friendlist[i].info_size > SAVED_FRIEND_REQUEST_SIZE) {\n                    memcpy(temp.info, m->friendlist[i].info, SAVED_FRIEND_REQUEST_SIZE);\n                } else {\n                    memcpy(temp.info, m->friendlist[i].info, m->friendlist[i].info_size);\n                }\n\n                temp.info_size = htons(m->friendlist[i].info_size);\n                temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam;\n            } else {\n                memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length);\n                temp.name_length = htons(m->friendlist[i].name_length);\n                memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length);\n                temp.statusmessage_length = htons(m->friendlist[i].statusmessage_length);\n                temp.userstatus = m->friendlist[i].userstatus;\n\n                uint8_t last_seen_time[sizeof(uint64_t)];\n                memcpy(last_seen_time, &m->friendlist[i].last_seen_time, sizeof(uint64_t));\n                host_to_net(last_seen_time, sizeof(uint64_t));\n                memcpy(&temp.last_seen_time, last_seen_time, sizeof(uint64_t));\n            }\n\n            memcpy(data + num * sizeof(struct SAVED_FRIEND), &temp, sizeof(struct SAVED_FRIEND));\n            num++;\n        }\n    }\n\n    return num * sizeof(struct SAVED_FRIEND);\n}\n\nstatic int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length)\n{\n    if (length % sizeof(struct SAVED_FRIEND) != 0) {\n        return -1;\n    }\n\n    uint32_t num = length / sizeof(struct SAVED_FRIEND);\n    uint32_t i;\n\n    for (i = 0; i < num; ++i) {\n        struct SAVED_FRIEND temp;\n        memcpy(&temp, data + i * sizeof(struct SAVED_FRIEND), sizeof(struct SAVED_FRIEND));\n\n        if (temp.status >= 3) {\n            int fnum = m_addfriend_norequest(m, temp.real_pk);\n\n            if (fnum < 0)\n                continue;\n\n            setfriendname(m, fnum, temp.name, ntohs(temp.name_length));\n            set_friend_statusmessage(m, fnum, temp.statusmessage, ntohs(temp.statusmessage_length));\n            set_friend_userstatus(m, fnum, temp.userstatus);\n            uint8_t last_seen_time[sizeof(uint64_t)];\n            memcpy(last_seen_time, &temp.last_seen_time, sizeof(uint64_t));\n            net_to_host(last_seen_time, sizeof(uint64_t));\n            memcpy(&m->friendlist[fnum].last_seen_time, last_seen_time, sizeof(uint64_t));\n        } else if (temp.status != 0) {\n            /* TODO: This is not a good way to do this. */\n            uint8_t address[FRIEND_ADDRESS_SIZE];\n            id_copy(address, temp.real_pk);\n            memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t));\n            uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));\n            memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));\n            m_addfriend(m, address, temp.info, ntohs(temp.info_size));\n        }\n    }\n\n    return num;\n}\n\n/*  return size of the messenger data (for saving) */\nuint32_t messenger_size(const Messenger *m)\n{\n    uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2;\n    return   size32 * 2                                      // global cookie\n             + sizesubhead + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES\n             + sizesubhead + DHT_size(m->dht)                  // DHT\n             + sizesubhead + saved_friendslist_size(m)         // Friendlist itself.\n             + sizesubhead + m->name_length                    // Own nickname.\n             + sizesubhead + m->statusmessage_length           // status message\n             + sizesubhead + 1                                 // status\n             + sizesubhead + NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6) //TCP relays\n             + sizesubhead + NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6) //saved path nodes\n             + sizesubhead;\n}\n\nstatic uint8_t *z_state_save_subheader(uint8_t *data, uint32_t len, uint16_t type)\n{\n    host_to_lendian32(data, len);\n    data += sizeof(uint32_t);\n    host_to_lendian32(data, (host_tolendian16(MESSENGER_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type));\n    data += sizeof(uint32_t);\n    return data;\n}\n\n/* Save the messenger in data of size Messenger_size(). */\nvoid messenger_save(const Messenger *m, uint8_t *data)\n{\n    memset(data, 0, messenger_size(m));\n\n    uint32_t len;\n    uint16_t type;\n    uint32_t size32 = sizeof(uint32_t);\n\n    memset(data, 0, size32);\n    data += size32;\n    host_to_lendian32(data, MESSENGER_STATE_COOKIE_GLOBAL);\n    data += size32;\n\n#ifdef DEBUG\n    assert(sizeof(get_nospam(&(m->fr))) == sizeof(uint32_t));\n#endif\n    len = size32 + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;\n    type = MESSENGER_STATE_TYPE_NOSPAMKEYS;\n    data = z_state_save_subheader(data, len, type);\n    *(uint32_t *)data = get_nospam(&(m->fr));\n    save_keys(m->net_crypto, data + size32);\n    data += len;\n\n    len = saved_friendslist_size(m);\n    type = MESSENGER_STATE_TYPE_FRIENDS;\n    data = z_state_save_subheader(data, len, type);\n    friends_list_save(m, data);\n    data += len;\n\n    len = m->name_length;\n    type = MESSENGER_STATE_TYPE_NAME;\n    data = z_state_save_subheader(data, len, type);\n    memcpy(data, m->name, len);\n    data += len;\n\n    len = m->statusmessage_length;\n    type = MESSENGER_STATE_TYPE_STATUSMESSAGE;\n    data = z_state_save_subheader(data, len, type);\n    memcpy(data, m->statusmessage, len);\n    data += len;\n\n    len = 1;\n    type = MESSENGER_STATE_TYPE_STATUS;\n    data = z_state_save_subheader(data, len, type);\n    *data = m->userstatus;\n    data += len;\n\n    len = DHT_size(m->dht);\n    type = MESSENGER_STATE_TYPE_DHT;\n    data = z_state_save_subheader(data, len, type);\n    DHT_save(m->dht, data);\n    data += len;\n\n    Node_format relays[NUM_SAVED_TCP_RELAYS];\n    type = MESSENGER_STATE_TYPE_TCP_RELAY;\n    uint8_t *temp_data = data;\n    data = z_state_save_subheader(temp_data, 0, type);\n    unsigned int num = copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS);\n    int l = pack_nodes(data, NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6), relays, num);\n\n    if (l > 0) {\n        len = l;\n        data = z_state_save_subheader(temp_data, len, type);\n        data += len;\n    }\n\n    Node_format nodes[NUM_SAVED_PATH_NODES];\n    type = MESSENGER_STATE_TYPE_PATH_NODE;\n    temp_data = data;\n    data = z_state_save_subheader(data, 0, type);\n    memset(nodes, 0, sizeof(nodes));\n    num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES);\n    l = pack_nodes(data, NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6), nodes, num);\n\n    if (l > 0) {\n        len = l;\n        data = z_state_save_subheader(temp_data, len, type);\n        data += len;\n    }\n\n    z_state_save_subheader(data, 0, MESSENGER_STATE_TYPE_END);\n}\n\nstatic int messenger_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type)\n{\n    Messenger *m = outer;\n\n    switch (type) {\n        case MESSENGER_STATE_TYPE_NOSPAMKEYS:\n            if (length == crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t)) {\n                set_nospam(&(m->fr), *(uint32_t *)data);\n                load_secret_key(m->net_crypto, (&data[sizeof(uint32_t)]) + crypto_box_PUBLICKEYBYTES);\n\n                if (public_key_cmp((&data[sizeof(uint32_t)]), m->net_crypto->self_public_key) != 0) {\n                    return -1;\n                }\n            } else\n                return -1;    /* critical */\n\n            break;\n\n        case MESSENGER_STATE_TYPE_DHT:\n            DHT_load(m->dht, data, length);\n            break;\n\n        case MESSENGER_STATE_TYPE_FRIENDS:\n            friends_list_load(m, data, length);\n            break;\n\n        case MESSENGER_STATE_TYPE_NAME:\n            if ((length > 0) && (length <= MAX_NAME_LENGTH)) {\n                setname(m, data, length);\n            }\n\n            break;\n\n        case MESSENGER_STATE_TYPE_STATUSMESSAGE:\n            if ((length > 0) && (length < MAX_STATUSMESSAGE_LENGTH)) {\n                m_set_statusmessage(m, data, length);\n            }\n\n            break;\n\n        case MESSENGER_STATE_TYPE_STATUS:\n            if (length == 1) {\n                m_set_userstatus(m, *data);\n            }\n\n            break;\n\n        case MESSENGER_STATE_TYPE_TCP_RELAY: {\n            if (length == 0) {\n                break;\n            }\n\n            unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, 0, data, length, 1);\n            m->has_added_relays = 0;\n\n            break;\n        }\n\n        case MESSENGER_STATE_TYPE_PATH_NODE: {\n            Node_format nodes[NUM_SAVED_PATH_NODES];\n\n            if (length == 0) {\n                break;\n            }\n\n            int i, num = unpack_nodes(nodes, NUM_SAVED_PATH_NODES, 0, data, length, 0);\n\n            for (i = 0; i < num; ++i) {\n                onion_add_bs_path_node(m->onion_c, nodes[i].ip_port, nodes[i].public_key);\n            }\n\n            break;\n        }\n\n        case MESSENGER_STATE_TYPE_END: {\n            if (length != 0) {\n                return -1;\n            }\n\n            return -2;\n            break;\n        }\n\n#ifdef DEBUG\n\n        default:\n            fprintf(stderr, \"Load state: contains unrecognized part (len %u, type %u)\\n\",\n                    length, type);\n            break;\n#endif\n    }\n\n    return 0;\n}\n\n/* Load the messenger from data of size length. */\nint messenger_load(Messenger *m, const uint8_t *data, uint32_t length)\n{\n    uint32_t data32[2];\n    uint32_t cookie_len = sizeof(data32);\n\n    if (length < cookie_len)\n        return -1;\n\n    memcpy(data32, data, sizeof(uint32_t));\n    lendian_to_host32(data32 + 1, data + sizeof(uint32_t));\n\n    if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL))\n        return load_state(messenger_load_state_callback, m, data + cookie_len,\n                          length - cookie_len, MESSENGER_STATE_COOKIE_TYPE);\n    else\n        return -1;\n}\n\n/* Return the number of friends in the instance m.\n * You should use this to determine how much memory to allocate\n * for copy_friendlist. */\nuint32_t count_friendlist(const Messenger *m)\n{\n    uint32_t ret = 0;\n    uint32_t i;\n\n    for (i = 0; i < m->numfriends; i++) {\n        if (m->friendlist[i].status > 0) {\n            ret++;\n        }\n    }\n\n    return ret;\n}\n\n/* Copy a list of valid friend IDs into the array out_list.\n * If out_list is NULL, returns 0.\n * Otherwise, returns the number of elements copied.\n * If the array was too small, the contents\n * of out_list will be truncated to list_size. */\nuint32_t copy_friendlist(Messenger const *m, uint32_t *out_list, uint32_t list_size)\n{\n    if (!out_list)\n        return 0;\n\n    if (m->numfriends == 0) {\n        return 0;\n    }\n\n    uint32_t i;\n    uint32_t ret = 0;\n\n    for (i = 0; i < m->numfriends; i++) {\n        if (ret >= list_size) {\n            break; /* Abandon ship */\n        }\n\n        if (m->friendlist[i].status > 0) {\n            out_list[ret] = i;\n            ret++;\n        }\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "toxcore/Messenger.h",
    "content": "/* Messenger.h\n *\n * An implementation of a simple text chat only messenger on the tox network core.\n *\n * NOTE: All the text in the messages must be encoded using UTF-8\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef MESSENGER_H\n#define MESSENGER_H\n\n#include \"friend_requests.h\"\n#include \"friend_connection.h\"\n\n#define MAX_NAME_LENGTH 128\n/* TODO: this must depend on other variable. */\n#define MAX_STATUSMESSAGE_LENGTH 1007\n\n\n#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t))\n\nenum {\n    MESSAGE_NORMAL,\n    MESSAGE_ACTION\n};\n\n/* NOTE: Packet ids below 24 must never be used. */\n#define PACKET_ID_ONLINE 24\n#define PACKET_ID_OFFLINE 25\n#define PACKET_ID_NICKNAME 48\n#define PACKET_ID_STATUSMESSAGE 49\n#define PACKET_ID_USERSTATUS 50\n#define PACKET_ID_TYPING 51\n#define PACKET_ID_MESSAGE 64\n#define PACKET_ID_ACTION (PACKET_ID_MESSAGE + MESSAGE_ACTION) /* 65 */\n#define PACKET_ID_MSI 69\n#define PACKET_ID_FILE_SENDREQUEST 80\n#define PACKET_ID_FILE_CONTROL 81\n#define PACKET_ID_FILE_DATA 82\n#define PACKET_ID_INVITE_GROUPCHAT 96\n#define PACKET_ID_ONLINE_PACKET 97\n#define PACKET_ID_DIRECT_GROUPCHAT 98\n#define PACKET_ID_MESSAGE_GROUPCHAT 99\n#define PACKET_ID_LOSSY_GROUPCHAT 199\n\n/* All packets starting with a byte in this range can be used for anything. */\n#define PACKET_ID_LOSSLESS_RANGE_START 160\n#define PACKET_ID_LOSSLESS_RANGE_SIZE 32\n#define PACKET_LOSSY_AV_RESERVED 8 /* Number of lossy packet types at start of range reserved for A/V. */\n\ntypedef struct {\n    uint8_t ipv6enabled;\n    uint8_t udp_disabled;\n    TCP_Proxy_Info proxy_info;\n    uint16_t port_range[2];\n    uint16_t tcp_server_port;\n} Messenger_Options;\n\n\nstruct Receipts {\n    uint32_t packet_num;\n    uint32_t msg_id;\n    struct Receipts *next;\n};\n\n/* Status definitions. */\nenum {\n    NOFRIEND,\n    FRIEND_ADDED,\n    FRIEND_REQUESTED,\n    FRIEND_CONFIRMED,\n    FRIEND_ONLINE,\n};\n\n/* Errors for m_addfriend\n * FAERR - Friend Add Error\n */\nenum {\n    FAERR_TOOLONG = -1,\n    FAERR_NOMESSAGE = -2,\n    FAERR_OWNKEY = -3,\n    FAERR_ALREADYSENT = -4,\n    FAERR_BADCHECKSUM = -6,\n    FAERR_SETNEWNOSPAM = -7,\n    FAERR_NOMEM = -8\n};\n\n\n/* Default start timeout in seconds between friend requests. */\n#define FRIENDREQUEST_TIMEOUT 5;\n\nenum {\n    CONNECTION_NONE,\n    CONNECTION_TCP,\n    CONNECTION_UDP,\n    CONNECTION_UNKNOWN\n};\n\n/* USERSTATUS -\n * Represents userstatuses someone can have.\n */\n\ntypedef enum {\n    USERSTATUS_NONE,\n    USERSTATUS_AWAY,\n    USERSTATUS_BUSY,\n    USERSTATUS_INVALID\n}\nUSERSTATUS;\n\n#define FILE_ID_LENGTH 32\n\nstruct File_Transfers {\n    uint64_t size;\n    uint64_t transferred;\n    uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */\n    uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */\n    uint32_t last_packet_number; /* number of the last packet sent. */\n    uint64_t requested; /* total data requested by the request chunk callback */\n    unsigned int slots_allocated; /* number of slots allocated to this transfer. */\n    uint8_t id[FILE_ID_LENGTH];\n};\nenum {\n    FILESTATUS_NONE,\n    FILESTATUS_NOT_ACCEPTED,\n    FILESTATUS_TRANSFERRING,\n    //FILESTATUS_BROKEN,\n    FILESTATUS_FINISHED\n};\n\nenum {\n    FILE_PAUSE_NOT,\n    FILE_PAUSE_US,\n    FILE_PAUSE_OTHER,\n    FILE_PAUSE_BOTH\n};\n\n/* This cannot be bigger than 256 */\n#define MAX_CONCURRENT_FILE_PIPES 256\n\nenum {\n    FILECONTROL_ACCEPT,\n    FILECONTROL_PAUSE,\n    FILECONTROL_KILL,\n    FILECONTROL_SEEK\n};\n\nenum {\n    FILEKIND_DATA,\n    FILEKIND_AVATAR\n};\n\n\ntypedef struct Messenger Messenger;\n\ntypedef struct {\n    uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n    int friendcon_id;\n\n    uint64_t friendrequest_lastsent; // Time at which the last friend request was sent.\n    uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts.\n    uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online.\n    uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do.\n    uint8_t name[MAX_NAME_LENGTH];\n    uint16_t name_length;\n    uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have.\n    uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];\n    uint16_t statusmessage_length;\n    uint8_t statusmessage_sent;\n    USERSTATUS userstatus;\n    uint8_t userstatus_sent;\n    uint8_t user_istyping;\n    uint8_t user_istyping_sent;\n    uint8_t is_typing;\n    uint16_t info_size; // Length of the info.\n    uint32_t message_id; // a semi-unique id used in read receipts.\n    uint32_t friendrequest_nospam; // The nospam number used in the friend request.\n    uint64_t last_seen_time;\n    uint8_t last_connection_udp_tcp;\n    struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES];\n    unsigned int num_sending_files;\n    struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES];\n\n    struct {\n        int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object);\n        void *object;\n    } lossy_rtp_packethandlers[PACKET_LOSSY_AV_RESERVED];\n\n    struct Receipts *receipts_start;\n    struct Receipts *receipts_end;\n} Friend;\n\n\nstruct Messenger {\n\n    Networking_Core *net;\n    Net_Crypto *net_crypto;\n    DHT *dht;\n\n    Onion *onion;\n    Onion_Announce *onion_a;\n    Onion_Client *onion_c;\n\n    Friend_Connections *fr_c;\n\n    TCP_Server *tcp_server;\n    Friend_Requests fr;\n    uint8_t name[MAX_NAME_LENGTH];\n    uint16_t name_length;\n\n    uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH];\n    uint16_t statusmessage_length;\n\n    USERSTATUS userstatus;\n\n    Friend *friendlist;\n    uint32_t numfriends;\n\n#define NUM_SAVED_TCP_RELAYS 8\n    uint8_t has_added_relays; // If the first connection has occurred in do_messenger\n    Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config\n\n    void (*friend_message)(struct Messenger *m, uint32_t, unsigned int, const uint8_t *, size_t, void *);\n    void *friend_message_userdata;\n    void (*friend_namechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *);\n    void *friend_namechange_userdata;\n    void (*friend_statusmessagechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *);\n    void *friend_statusmessagechange_userdata;\n    void (*friend_userstatuschange)(struct Messenger *m, uint32_t, unsigned int, void *);\n    void *friend_userstatuschange_userdata;\n    void (*friend_typingchange)(struct Messenger *m, uint32_t, _Bool, void *);\n    void *friend_typingchange_userdata;\n    void (*read_receipt)(struct Messenger *m, uint32_t, uint32_t, void *);\n    void *read_receipt_userdata;\n    void (*friend_connectionstatuschange)(struct Messenger *m, uint32_t, unsigned int, void *);\n    void *friend_connectionstatuschange_userdata;\n    void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *);\n    void *friend_connectionstatuschange_internal_userdata;\n\n    void *group_chat_object; /* Set by new_groupchats()*/\n    void (*group_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t);\n    void (*group_message)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t);\n\n    void (*file_sendrequest)(struct Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t,\n                             void *);\n    void *file_sendrequest_userdata;\n    void (*file_filecontrol)(struct Messenger *m, uint32_t, uint32_t, unsigned int, void *);\n    void *file_filecontrol_userdata;\n    void (*file_filedata)(struct Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *);\n    void *file_filedata_userdata;\n    void (*file_reqchunk)(struct Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *);\n    void *file_reqchunk_userdata;\n\n    void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *);\n    void *msi_packet_userdata;\n\n    void (*lossy_packethandler)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *);\n    void *lossy_packethandler_userdata;\n    void (*lossless_packethandler)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *);\n    void *lossless_packethandler_userdata;\n\n    void (*core_connection_change)(struct Messenger *m, unsigned int, void *);\n    void *core_connection_change_userdata;\n    unsigned int last_connection_status;\n\n    Messenger_Options options;\n};\n\n/* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)]\n *\n *  return FRIEND_ADDRESS_SIZE byte address to give to others.\n */\nvoid getaddress(const Messenger *m, uint8_t *address);\n\n/* Add a friend.\n * Set the data that will be sent along with friend request.\n * 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.\n * data is the data and length is the length.\n *\n *  return the friend number if success.\n *  return -1 if message length is too long.\n *  return -2 if no message (message length must be >= 1 byte).\n *  return -3 if user's own key.\n *  return -4 if friend request already sent or already a friend.\n *  return -6 if bad checksum in address.\n *  return -7 if the friend was already there but the nospam was different.\n *  (the nospam for that friend was set to the new one).\n *  return -8 if increasing the friend list size fails.\n */\nint32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length);\n\n\n/* Add a friend without sending a friendrequest.\n *  return the friend number if success.\n *  return -3 if user's own key.\n *  return -4 if friend request already sent or already a friend.\n *  return -6 if bad checksum in address.\n *  return -8 if increasing the friend list size fails.\n */\nint32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk);\n\n/*  return the friend number associated to that client id.\n *  return -1 if no such friend.\n */\nint32_t getfriend_id(const Messenger *m, const uint8_t *real_pk);\n\n/* Copies the public key associated to that friend id into real_pk buffer.\n * Make sure that real_pk is of size crypto_box_PUBLICKEYBYTES.\n *\n *  return 0 if success\n *  return -1 if failure\n */\nint get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk);\n\n/*  return friend connection id on success.\n *  return -1 if failure.\n */\nint getfriendcon_id(const Messenger *m, int32_t friendnumber);\n\n/* Remove a friend.\n *\n *  return 0 if success\n *  return -1 if failure\n */\nint m_delfriend(Messenger *m, int32_t friendnumber);\n\n/* Checks friend's connecting status.\n *\n *  return CONNECTION_UDP (2) if friend is directly connected to us (Online UDP).\n *  return CONNECTION_TCP (1) if friend is connected to us (Online TCP).\n *  return CONNECTION_NONE (0) if friend is not connected to us (Offline).\n *  return -1 on failure.\n */\nint m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber);\n\n/* Checks if there exists a friend with given friendnumber.\n *\n *  return 1 if friend exists.\n *  return 0 if friend doesn't exist.\n */\nint m_friend_exists(const Messenger *m, int32_t friendnumber);\n\n/* Send a message of type to an online friend.\n *\n * return -1 if friend not valid.\n * return -2 if too large.\n * return -3 if friend not online.\n * return -4 if send failed (because queue is full).\n * return -5 if bad type.\n * return 0 if success.\n *\n *  the value in message_id will be passed to your read_receipt callback when the other receives the message.\n */\nint m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length,\n                           uint32_t *message_id);\n\n\n/* Set the name and name_length of a friend.\n * name must be a string of maximum MAX_NAME_LENGTH length.\n * length must be at least 1 byte.\n * length is the length of name with the NULL terminator.\n *\n *  return 0 if success.\n *  return -1 if failure.\n */\nint setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length);\n\n/* Set our nickname.\n * name must be a string of maximum MAX_NAME_LENGTH length.\n * length must be at least 1 byte.\n * length is the length of name with the NULL terminator.\n *\n *  return 0 if success.\n *  return -1 if failure.\n */\nint setname(Messenger *m, const uint8_t *name, uint16_t length);\n\n/*\n * Get your nickname.\n * m - The messenger context to use.\n * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.\n *\n *  return length of the name.\n *  return 0 on error.\n */\nuint16_t getself_name(const Messenger *m, uint8_t *name);\n\n/* Get name of friendnumber and put it in name.\n * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.\n *\n *  return length of name if success.\n *  return -1 if failure.\n */\nint getname(const Messenger *m, int32_t friendnumber, uint8_t *name);\n\n/*  return the length of name, including null on success.\n *  return -1 on failure.\n */\nint m_get_name_size(const Messenger *m, int32_t friendnumber);\nint m_get_self_name_size(const Messenger *m);\n\n/* Set our user status.\n * You are responsible for freeing status after.\n *\n *  returns 0 on success.\n *  returns -1 on failure.\n */\nint m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length);\nint m_set_userstatus(Messenger *m, uint8_t status);\n\n/*  return the length of friendnumber's status message, including null on success.\n *  return -1 on failure.\n */\nint m_get_statusmessage_size(const Messenger *m, int32_t friendnumber);\nint m_get_self_statusmessage_size(const Messenger *m);\n\n/* Copy friendnumber's status message into buf, truncating if size is over maxlen.\n * Get the size you need to allocate from m_get_statusmessage_size.\n * The self variant will copy our own status message.\n *\n * returns the length of the copied data on success\n * retruns -1 on failure.\n */\nint m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen);\nint m_copy_self_statusmessage(const Messenger *m, uint8_t *buf);\n\n/*  return one of USERSTATUS values.\n *  Values unknown to your application should be represented as USERSTATUS_NONE.\n *  As above, the self variant will return our own USERSTATUS.\n *  If friendnumber is invalid, this shall return USERSTATUS_INVALID.\n */\nuint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber);\nuint8_t m_get_self_userstatus(const Messenger *m);\n\n\n/* returns timestamp of last time friendnumber was seen online or 0 if never seen.\n * if friendnumber is invalid this function will return UINT64_MAX.\n */\nuint64_t m_get_last_online(const Messenger *m, int32_t friendnumber);\n\n/* Set our typing status for a friend.\n * You are responsible for turning it on or off.\n *\n * returns 0 on success.\n * returns -1 on failure.\n */\nint m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing);\n\n/* Get the typing status of a friend.\n *\n * returns 0 if friend is not typing.\n * returns 1 if friend is typing.\n */\nint m_get_istyping(const Messenger *m, int32_t friendnumber);\n\n/* Set the function that will be executed when a friend request is received.\n *  Function format is function(uint8_t * public_key, uint8_t * data, size_t length)\n */\nvoid m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t,\n                              void *), void *userdata);\n\n/* Set the function that will be executed when a message from a friend is received.\n *  Function format is: function(uint32_t friendnumber, unsigned int type, uint8_t * message, uint32_t length)\n */\nvoid m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, const uint8_t *,\n                              size_t, void *), void *userdata);\n\n/* Set the callback for name changes.\n *  Function(uint32_t friendnumber, uint8_t *newname, size_t length)\n *  You are not responsible for freeing newname.\n */\nvoid m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *),\n                           void *userdata);\n\n/* Set the callback for status message changes.\n *  Function(uint32_t friendnumber, uint8_t *newstatus, size_t length)\n *\n *  You are not responsible for freeing newstatus\n */\nvoid m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *),\n                              void *userdata);\n\n/* Set the callback for status type changes.\n *  Function(uint32_t friendnumber, USERSTATUS kind)\n */\nvoid m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *),\n                           void *userdata);\n\n/* Set the callback for typing changes.\n *  Function(uint32_t friendnumber, uint8_t is_typing)\n */\nvoid m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, _Bool, void *), void *userdata);\n\n/* Set the callback for read receipts.\n *  Function(uint32_t friendnumber, uint32_t receipt)\n *\n *  If you are keeping a record of returns from m_sendmessage,\n *  receipt might be one of those values, meaning the message\n *  has been received on the other side.\n *  Since core doesn't track ids for you, receipt may not correspond to any message.\n *  In that case, you should discard it.\n */\nvoid m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *), void *userdata);\n\n/* Set the callback for connection status changes.\n *  function(uint32_t friendnumber, uint8_t status)\n *\n *  Status:\n *    0 -- friend went offline after being previously online.\n *    1 -- friend went online.\n *\n *  Note that this callback is not called when adding friends, thus the \"after\n *  being previously online\" part.\n *  It's assumed that when adding friends, their connection status is offline.\n */\nvoid m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *),\n                                 void *userdata);\n/* Same as previous but for internal A/V core usage only */\nvoid m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *),\n        void *userdata);\n\n\n/* Set the callback for typing changes.\n *  Function(unsigned int connection_status (0 = not connected, 1 = TCP only, 2 = UDP + TCP))\n */\nvoid m_callback_core_connection(Messenger *m, void (*function)(Messenger *m, unsigned int, void *), void *userdata);\n\n/**********GROUP CHATS************/\n\n/* Set the callback for group invites.\n *\n *  Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length)\n */\nvoid m_callback_group_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t));\n\n/* Send a group invite packet.\n *\n *  return 1 on success\n *  return 0 on failure\n */\nint send_group_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length);\n\n/****************FILE SENDING*****************/\n\n\n/* Set the callback for file send requests.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint32_t filetype, uint64_t filesize, uint8_t *filename, size_t filename_length, void *userdata)\n */\nvoid callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m,  uint32_t, uint32_t, uint32_t, uint64_t,\n                               const uint8_t *, size_t, void *), void *userdata);\n\n\n/* Set the callback for file control requests.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata)\n *\n */\nvoid callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *),\n                           void *userdata);\n\n/* Set the callback for file data.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata)\n *\n */\nvoid callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *,\n                        size_t, void *), void *userdata);\n\n/* Set the callback for file request chunk.\n *\n *  Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata)\n *\n */\nvoid callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *),\n                            void *userdata);\n\n\n/* Copy the file transfer file id to file_id\n *\n * return 0 on success.\n * return -1 if friend not valid.\n * return -2 if filenumber not valid\n */\nint file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id);\n\n/* Send a file send request.\n * Maximum filename length is 255 bytes.\n *  return file number on success\n *  return -1 if friend not found.\n *  return -2 if filename length invalid.\n *  return -3 if no more file sending slots left.\n *  return -4 if could not send packet (friend offline).\n *\n */\nlong int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize,\n                        const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length);\n\n/* Send a file control request.\n *\n *  return 0 on success\n *  return -1 if friend not valid.\n *  return -2 if friend not online.\n *  return -3 if file number invalid.\n *  return -4 if file control is bad.\n *  return -5 if file already paused.\n *  return -6 if resume file failed because it was only paused by the other.\n *  return -7 if resume file failed because it wasn't paused.\n *  return -8 if packet failed to send.\n */\nint file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control);\n\n/* Send a seek file control request.\n *\n *  return 0 on success\n *  return -1 if friend not valid.\n *  return -2 if friend not online.\n *  return -3 if file number invalid.\n *  return -4 if not receiving file.\n *  return -5 if file status wrong.\n *  return -6 if position bad.\n *  return -8 if packet failed to send.\n */\nint file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position);\n\n/* Send file data.\n *\n *  return 0 on success\n *  return -1 if friend not valid.\n *  return -2 if friend not online.\n *  return -3 if filenumber invalid.\n *  return -4 if file transfer not transferring.\n *  return -5 if bad data size.\n *  return -6 if packet queue full.\n *  return -7 if wrong position.\n */\nint file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data,\n              uint16_t length);\n\n/* Give the number of bytes left to be sent/received.\n *\n *  send_receive is 0 if we want the sending files, 1 if we want the receiving.\n *\n *  return number of bytes remaining to be sent/received on success\n *  return 0 on failure\n */\nuint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive);\n\n/*************** A/V related ******************/\n\n/* Set the callback for msi packets.\n *\n *  Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata)\n */\nvoid m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *),\n                           void *userdata);\n\n/* Send an msi packet.\n *\n *  return 1 on success\n *  return 0 on failure\n */\nint m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length);\n\n/* Set handlers for lossy rtp packets.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, int (*packet_handler_callback)(Messenger *m,\n                          uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object), void *object);\n\n/**********************************************/\n\n/* Set handlers for custom lossy packets.\n *\n */\nvoid custom_lossy_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m,\n        uint32_t friendnumber, const uint8_t *data, size_t len, void *object), void *object);\n\n/* High level function to send custom lossy packets.\n *\n * return -1 if friend invalid.\n * return -2 if length wrong.\n * return -3 if first byte invalid.\n * return -4 if friend offline.\n * return -5 if packet failed to send because of other error.\n * return 0 on success.\n */\nint send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length);\n\n\n/* Set handlers for custom lossless packets.\n *\n */\nvoid custom_lossless_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m,\n        uint32_t friendnumber, const uint8_t *data, size_t len, void *object), void *object);\n\n/* High level function to send custom lossless packets.\n *\n * return -1 if friend invalid.\n * return -2 if length wrong.\n * return -3 if first byte invalid.\n * return -4 if friend offline.\n * return -5 if packet failed to send because of other error.\n * return 0 on success.\n */\nint send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length);\n\n/**********************************************/\n\nenum {\n    MESSENGER_ERROR_NONE,\n    MESSENGER_ERROR_PORT,\n    MESSENGER_ERROR_TCP_SERVER,\n    MESSENGER_ERROR_OTHER\n};\n\n/* Run this at startup.\n *  return allocated instance of Messenger on success.\n *  return 0 if there are problems.\n *\n *  if error is not NULL it will be set to one of the values in the enum above.\n */\nMessenger *new_messenger(Messenger_Options *options, unsigned int *error);\n\n/* Run this before closing shop\n * Free all datastructures.\n */\nvoid kill_messenger(Messenger *m);\n\n/* The main loop that needs to be run at least 20 times per second. */\nvoid do_messenger(Messenger *m);\n\n/* Return the time in milliseconds before do_messenger() should be called again\n * for optimal performance.\n *\n * returns time (in ms) before the next do_messenger() needs to be run on success.\n */\nuint32_t messenger_run_interval(const Messenger *m);\n\n/* SAVING AND LOADING FUNCTIONS: */\n\n/* return size of the messenger data (for saving). */\nuint32_t messenger_size(const Messenger *m);\n\n/* Save the messenger in data (must be allocated memory of size Messenger_size()) */\nvoid messenger_save(const Messenger *m, uint8_t *data);\n\n/* Load the messenger from data of size length. */\nint messenger_load(Messenger *m, const uint8_t *data, uint32_t length);\n\n/* Return the number of friends in the instance m.\n * You should use this to determine how much memory to allocate\n * for copy_friendlist. */\nuint32_t count_friendlist(const Messenger *m);\n\n/* Copy a list of valid friend IDs into the array out_list.\n * If out_list is NULL, returns 0.\n * Otherwise, returns the number of elements copied.\n * If the array was too small, the contents\n * of out_list will be truncated to list_size. */\nuint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size);\n\n#endif\n"
  },
  {
    "path": "toxcore/TCP_client.c",
    "content": "/*\n* TCP_client.c -- Implementation of the TCP relay client part of Tox.\n*\n*  Copyright (C) 2014 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"TCP_client.h\"\n\n#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)\n#include <sys/ioctl.h>\n#endif\n\n#include \"util.h\"\n\n/* return 1 on success\n * return 0 on failure\n */\nstatic int connect_sock_to(sock_t sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info)\n{\n    if (proxy_info->proxy_type != TCP_PROXY_NONE) {\n        ip_port = proxy_info->ip_port;\n    }\n\n    struct sockaddr_storage addr = {0};\n\n    size_t addrsize;\n\n    if (ip_port.ip.family == AF_INET) {\n        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in);\n        addr4->sin_family = AF_INET;\n        addr4->sin_addr = ip_port.ip.ip4.in_addr;\n        addr4->sin_port = ip_port.port;\n    } else if (ip_port.ip.family == AF_INET6) {\n        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in6);\n        addr6->sin6_family = AF_INET6;\n        addr6->sin6_addr = ip_port.ip.ip6.in6_addr;\n        addr6->sin6_port = ip_port.port;\n    } else {\n        return 0;\n    }\n\n    /* nonblocking socket, connect will never return success */\n    connect(sock, (struct sockaddr *)&addr, addrsize);\n    return 1;\n}\n\n/* return 1 on success.\n * return 0 on failure.\n */\nstatic int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn)\n{\n    char one[] = \"CONNECT \";\n    char two[] = \" HTTP/1.1\\nHost: \";\n    char three[] = \"\\r\\n\\r\\n\";\n\n    char ip[INET6_ADDRSTRLEN];\n\n    if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) {\n        return 0;\n    }\n\n    const uint16_t port = ntohs(TCP_conn->ip_port.port);\n    const int written = snprintf((char *)TCP_conn->last_packet, MAX_PACKET_SIZE, \"%s%s:%hu%s%s:%hu%s\", one, ip, port, two,\n                                 ip, port, three);\n\n    if (written < 0 || MAX_PACKET_SIZE < written) {\n        return 0;\n    }\n\n    TCP_conn->last_packet_length = written;\n    TCP_conn->last_packet_sent = 0;\n\n    return 1;\n}\n\n/* return 1 on success.\n * return 0 if no data received.\n * return -1 on failure (connection refused).\n */\nstatic int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn)\n{\n    char success[] = \"200\";\n    uint8_t data[16]; // draining works the best if the length is a power of 2\n\n    int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1);\n\n    if (ret == -1) {\n        return 0;\n    }\n\n    data[sizeof(data) - 1] = 0;\n\n    if (strstr((char *)data, success)) {\n        // drain all data\n        unsigned int data_left = TCP_socket_data_recv_buffer(TCP_conn->sock);\n\n        if (data_left) {\n            uint8_t temp_data[data_left];\n            read_TCP_packet(TCP_conn->sock, temp_data, data_left);\n        }\n\n        return 1;\n    }\n\n    return -1;\n}\n\nstatic void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn)\n{\n    TCP_conn->last_packet[0] = 5; /* SOCKSv5 */\n    TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */\n    TCP_conn->last_packet[2] = 0; /* No authentication */\n\n    TCP_conn->last_packet_length = 3;\n    TCP_conn->last_packet_sent = 0;\n}\n\n/* return 1 on success.\n * return 0 if no data received.\n * return -1 on failure (connection refused).\n */\nstatic int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn)\n{\n    uint8_t data[2];\n    int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data));\n\n    if (ret == -1)\n        return 0;\n\n    if (data[0] == 5 && data[1] == 0) // FIXME magic numbers\n        return 1;\n\n    return -1;\n}\n\nstatic void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn)\n{\n    TCP_conn->last_packet[0] = 5; /* SOCKSv5 */\n    TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */\n    TCP_conn->last_packet[2] = 0; /* reserved, must be 0 */\n    uint16_t length = 3;\n\n    if (TCP_conn->ip_port.ip.family == AF_INET) {\n        TCP_conn->last_packet[3] = 1; /* IPv4 address */\n        ++length;\n        memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip4.uint8, sizeof(IP4));\n        length += sizeof(IP4);\n    } else {\n        TCP_conn->last_packet[3] = 4; /* IPv6 address */\n        ++length;\n        memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip6.uint8, sizeof(IP6));\n        length += sizeof(IP6);\n    }\n\n    memcpy(TCP_conn->last_packet + length, &TCP_conn->ip_port.port, sizeof(uint16_t));\n    length += sizeof(uint16_t);\n\n    TCP_conn->last_packet_length = length;\n    TCP_conn->last_packet_sent = 0;\n}\n\n/* return 1 on success.\n * return 0 if no data received.\n * return -1 on failure (connection refused).\n */\nstatic int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn)\n{\n    if (TCP_conn->ip_port.ip.family == AF_INET) {\n        uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)];\n        int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data));\n\n        if (ret == -1)\n            return 0;\n\n        if (data[0] == 5 && data[1] == 0)\n            return 1;\n\n    } else {\n        uint8_t data[4 + sizeof(IP6) + sizeof(uint16_t)];\n        int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data));\n\n        if (ret == -1)\n            return 0;\n\n        if (data[0] == 5 && data[1] == 0)\n            return 1;\n    }\n\n    return -1;\n}\n\n/* return 0 on success.\n * return -1 on failure.\n */\nstatic int generate_handshake(TCP_Client_Connection *TCP_conn)\n{\n    uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES];\n    crypto_box_keypair(plain, TCP_conn->temp_secret_key);\n    random_nonce(TCP_conn->sent_nonce);\n    memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES);\n    memcpy(TCP_conn->last_packet, TCP_conn->self_public_key, crypto_box_PUBLICKEYBYTES);\n    new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES);\n    int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain,\n                                     sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);\n\n    if (len != sizeof(plain) + crypto_box_MACBYTES)\n        return -1;\n\n    TCP_conn->last_packet_length = crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + sizeof(plain) + crypto_box_MACBYTES;\n    TCP_conn->last_packet_sent = 0;\n    return 0;\n}\n\n/* data must be of length TCP_SERVER_HANDSHAKE_SIZE\n *\n * return 0 on success.\n * return -1 on failure.\n */\nstatic int handle_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *data)\n{\n    uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES];\n    int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES,\n                                     TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain);\n\n    if (len != sizeof(plain))\n        return -1;\n\n    memcpy(TCP_conn->recv_nonce, plain + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);\n    encrypt_precompute(plain, TCP_conn->temp_secret_key, TCP_conn->shared_key);\n    sodium_memzero(TCP_conn->temp_secret_key, crypto_box_SECRETKEYBYTES);\n    return 0;\n}\n\n/* return 0 if pending data was sent completely\n * return -1 if it wasn't\n */\nstatic int send_pending_data_nonpriority(TCP_Client_Connection *con)\n{\n    if (con->last_packet_length == 0) {\n        return 0;\n    }\n\n    uint16_t left = con->last_packet_length - con->last_packet_sent;\n    int len = send(con->sock, con->last_packet + con->last_packet_sent, left, MSG_NOSIGNAL);\n\n    if (len <= 0)\n        return -1;\n\n    if (len == left) {\n        con->last_packet_length = 0;\n        con->last_packet_sent = 0;\n        return 0;\n    }\n\n    con->last_packet_sent += len;\n    return -1;\n}\n\n/* return 0 if pending data was sent completely\n * return -1 if it wasn't\n */\nstatic int send_pending_data(TCP_Client_Connection *con)\n{\n    /* finish sending current non-priority packet */\n    if (send_pending_data_nonpriority(con) == -1) {\n        return -1;\n    }\n\n    TCP_Priority_List *p = con->priority_queue_start;\n\n    while (p) {\n        uint16_t left = p->size - p->sent;\n        int len = send(con->sock, p->data + p->sent, left, MSG_NOSIGNAL);\n\n        if (len != left) {\n            if (len > 0) {\n                p->sent += len;\n            }\n\n            break;\n        }\n\n        TCP_Priority_List *pp = p;\n        p = p->next;\n        free(pp);\n    }\n\n    con->priority_queue_start = p;\n\n    if (!p) {\n        con->priority_queue_end = NULL;\n        return 0;\n    }\n\n    return -1;\n}\n\n/* return 0 on failure (only if malloc fails)\n * return 1 on success\n */\nstatic _Bool add_priority(TCP_Client_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent)\n{\n    TCP_Priority_List *p = con->priority_queue_end, *new;\n    new = malloc(sizeof(TCP_Priority_List) + size);\n\n    if (!new) {\n        return 0;\n    }\n\n    new->next = NULL;\n    new->size = size;\n    new->sent = sent;\n    memcpy(new->data, packet, size);\n\n    if (p) {\n        p->next = new;\n    } else {\n        con->priority_queue_start = new;\n    }\n\n    con->priority_queue_end = new;\n    return 1;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int write_packet_TCP_secure_connection(TCP_Client_Connection *con, const uint8_t *data, uint16_t length,\n        _Bool priority)\n{\n    if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE)\n        return -1;\n\n    _Bool sendpriority = 1;\n\n    if (send_pending_data(con) == -1) {\n        if (priority) {\n            sendpriority = 0;\n        } else {\n            return 0;\n        }\n    }\n\n    uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES];\n\n    uint16_t c_length = htons(length + crypto_box_MACBYTES);\n    memcpy(packet, &c_length, sizeof(uint16_t));\n    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));\n\n    if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))\n        return -1;\n\n    if (priority) {\n        len = sendpriority ? send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL) : 0;\n\n        if (len <= 0) {\n            len = 0;\n        }\n\n        increment_nonce(con->sent_nonce);\n\n        if ((unsigned int)len == sizeof(packet)) {\n            return 1;\n        }\n\n        return add_priority(con, packet, sizeof(packet), len);\n    }\n\n    len = send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL);\n\n    if (len <= 0)\n        return 0;\n\n    increment_nonce(con->sent_nonce);\n\n    if ((unsigned int)len == sizeof(packet))\n        return 1;\n\n    memcpy(con->last_packet, packet, sizeof(packet));\n    con->last_packet_length = sizeof(packet);\n    con->last_packet_sent = len;\n    return 1;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nint send_routing_request(TCP_Client_Connection *con, uint8_t *public_key)\n{\n    uint8_t packet[1 + crypto_box_PUBLICKEYBYTES];\n    packet[0] = TCP_PACKET_ROUTING_REQUEST;\n    memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);\n    return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1);\n}\n\nvoid routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id,\n                              const uint8_t *public_key), void *object)\n{\n    con->response_callback = response_callback;\n    con->response_callback_object = object;\n}\n\nvoid routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number,\n                            uint8_t connection_id, uint8_t status), void *object)\n{\n    con->status_callback = status_callback;\n    con->status_callback_object = object;\n}\n\nstatic int send_ping_response(TCP_Client_Connection *con);\nstatic int send_ping_request(TCP_Client_Connection *con);\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure.\n */\nint send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length)\n{\n    if (con_id >= NUM_CLIENT_CONNECTIONS)\n        return -1;\n\n    if (con->connections[con_id].status != 2)\n        return -1;\n\n    if (send_ping_response(con) == 0 || send_ping_request(con) == 0)\n        return 0;\n\n    uint8_t packet[1 + length];\n    packet[0] = con_id + NUM_RESERVED_PORTS;\n    memcpy(packet + 1, data, length);\n    return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 0);\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure.\n */\nint send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length)\n{\n    if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH)\n        return -1;\n\n    uint8_t packet[1 + crypto_box_PUBLICKEYBYTES + length];\n    packet[0] = TCP_PACKET_OOB_SEND;\n    memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, data, length);\n    return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 0);\n}\n\n\n/* Set the number that will be used as an argument in the callbacks related to con_id.\n *\n * When not set by this function, the number is ~0.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number)\n{\n    if (con_id >= NUM_CLIENT_CONNECTIONS)\n        return -1;\n\n    if (con->connections[con_id].status == 0)\n        return -1;\n\n    con->connections[con_id].number = number;\n    return 0;\n}\n\nvoid routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number,\n                          uint8_t connection_id, const uint8_t *data, uint16_t length), void *object)\n{\n    con->data_callback = data_callback;\n    con->data_callback_object = object;\n}\n\nvoid oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, const uint8_t *public_key,\n                      const uint8_t *data, uint16_t length), void *object)\n{\n    con->oob_data_callback = oob_data_callback;\n    con->oob_data_callback_object = object;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int send_disconnect_notification(TCP_Client_Connection *con, uint8_t id)\n{\n    uint8_t packet[1 + 1];\n    packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION;\n    packet[1] = id;\n    return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1);\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int send_ping_request(TCP_Client_Connection *con)\n{\n    if (!con->ping_request_id)\n        return 1;\n\n    uint8_t packet[1 + sizeof(uint64_t)];\n    packet[0] = TCP_PACKET_PING;\n    memcpy(packet + 1, &con->ping_request_id, sizeof(uint64_t));\n    int ret;\n\n    if ((ret = write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1)) == 1) {\n        con->ping_request_id = 0;\n    }\n\n    return ret;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int send_ping_response(TCP_Client_Connection *con)\n{\n    if (!con->ping_response_id)\n        return 1;\n\n    uint8_t packet[1 + sizeof(uint64_t)];\n    packet[0] = TCP_PACKET_PONG;\n    memcpy(packet + 1, &con->ping_response_id, sizeof(uint64_t));\n    int ret;\n\n    if ((ret = write_packet_TCP_secure_connection(con, packet, sizeof(packet), 1)) == 1) {\n        con->ping_response_id = 0;\n    }\n\n    return ret;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nint send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id)\n{\n    if (con_id >= NUM_CLIENT_CONNECTIONS)\n        return -1;\n\n    con->connections[con_id].status = 0;\n    con->connections[con_id].number = 0;\n    return send_disconnect_notification(con, con_id + NUM_RESERVED_PORTS);\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nint send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length)\n{\n    uint8_t packet[1 + length];\n    packet[0] = TCP_PACKET_ONION_REQUEST;\n    memcpy(packet + 1, data, length);\n    return write_packet_TCP_secure_connection(con, packet, sizeof(packet), 0);\n}\n\nvoid onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, const uint8_t *data,\n                            uint16_t length), void *object)\n{\n    con->onion_callback = onion_callback;\n    con->onion_callback_object = object;\n}\n\n/* Create new TCP connection to ip_port/public_key\n */\nTCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key,\n        const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info)\n{\n    if (networking_at_startup() != 0) {\n        return NULL;\n    }\n\n    if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6)\n        return NULL;\n\n    uint8_t family = ip_port.ip.family;\n\n    TCP_Proxy_Info default_proxyinfo;\n\n    if (proxy_info == NULL) {\n        default_proxyinfo.proxy_type = TCP_PROXY_NONE;\n        proxy_info = &default_proxyinfo;\n    }\n\n    if (proxy_info->proxy_type != TCP_PROXY_NONE) {\n        family = proxy_info->ip_port.ip.family;\n    }\n\n    sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP);\n\n    if (!sock_valid(sock)) {\n        return NULL;\n    }\n\n    if (!set_socket_nosigpipe(sock)) {\n        kill_sock(sock);\n        return 0;\n    }\n\n    if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port, proxy_info))) {\n        kill_sock(sock);\n        return NULL;\n    }\n\n    TCP_Client_Connection *temp = calloc(sizeof(TCP_Client_Connection), 1);\n\n    if (temp == NULL) {\n        kill_sock(sock);\n        return NULL;\n    }\n\n    temp->sock = sock;\n    memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(temp->self_public_key, self_public_key, crypto_box_PUBLICKEYBYTES);\n    encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key);\n    temp->ip_port = ip_port;\n    temp->proxy_info = *proxy_info;\n\n    switch (proxy_info->proxy_type) {\n        case TCP_PROXY_HTTP:\n            temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING;\n            proxy_http_generate_connection_request(temp);\n            break;\n\n        case TCP_PROXY_SOCKS5:\n            temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING;\n            proxy_socks5_generate_handshake(temp);\n            break;\n\n        case TCP_PROXY_NONE:\n            temp->status = TCP_CLIENT_CONNECTING;\n\n            if (generate_handshake(temp) == -1) {\n                kill_sock(sock);\n                free(temp);\n                return NULL;\n            }\n\n            break;\n    }\n\n    temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT;\n\n    return temp;\n}\n\n/* return 0 on success\n * return -1 on failure\n */\nstatic int handle_TCP_packet(TCP_Client_Connection *conn, const uint8_t *data, uint16_t length)\n{\n    if (length <= 1)\n        return -1;\n\n    switch (data[0]) {\n        case TCP_PACKET_ROUTING_RESPONSE: {\n            if (length != 1 + 1 + crypto_box_PUBLICKEYBYTES)\n                return -1;\n\n            if (data[1] < NUM_RESERVED_PORTS)\n                return 0;\n\n            uint8_t con_id = data[1] - NUM_RESERVED_PORTS;\n\n            if (conn->connections[con_id].status != 0)\n                return 0;\n\n            conn->connections[con_id].status = 1;\n            conn->connections[con_id].number = ~0;\n            memcpy(conn->connections[con_id].public_key, data + 2, crypto_box_PUBLICKEYBYTES);\n\n            if (conn->response_callback)\n                conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key);\n\n            return 0;\n        }\n\n        case TCP_PACKET_CONNECTION_NOTIFICATION: {\n            if (length != 1 + 1)\n                return -1;\n\n            if (data[1] < NUM_RESERVED_PORTS)\n                return -1;\n\n            uint8_t con_id = data[1] - NUM_RESERVED_PORTS;\n\n            if (conn->connections[con_id].status != 1)\n                return 0;\n\n            conn->connections[con_id].status = 2;\n\n            if (conn->status_callback)\n                conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id,\n                                      conn->connections[con_id].status);\n\n            return 0;\n        }\n\n        case TCP_PACKET_DISCONNECT_NOTIFICATION: {\n            if (length != 1 + 1)\n                return -1;\n\n            if (data[1] < NUM_RESERVED_PORTS)\n                return -1;\n\n            uint8_t con_id = data[1] - NUM_RESERVED_PORTS;\n\n            if (conn->connections[con_id].status == 0)\n                return 0;\n\n            if (conn->connections[con_id].status != 2)\n                return 0;\n\n            conn->connections[con_id].status = 1;\n\n            if (conn->status_callback)\n                conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id,\n                                      conn->connections[con_id].status);\n\n            return 0;\n        }\n\n        case TCP_PACKET_PING: {\n            if (length != 1 + sizeof(uint64_t))\n                return -1;\n\n            uint64_t ping_id;\n            memcpy(&ping_id, data + 1, sizeof(uint64_t));\n            conn->ping_response_id = ping_id;\n            send_ping_response(conn);\n            return 0;\n        }\n\n        case TCP_PACKET_PONG: {\n            if (length != 1 + sizeof(uint64_t))\n                return -1;\n\n            uint64_t ping_id;\n            memcpy(&ping_id, data + 1, sizeof(uint64_t));\n\n            if (ping_id) {\n                if (ping_id == conn->ping_id) {\n                    conn->ping_id = 0;\n                }\n\n                return 0;\n            } else {\n                return -1;\n            }\n        }\n\n        case TCP_PACKET_OOB_RECV: {\n            if (length <= 1 + crypto_box_PUBLICKEYBYTES)\n                return -1;\n\n            if (conn->oob_data_callback)\n                conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES,\n                                        length - (1 + crypto_box_PUBLICKEYBYTES));\n\n            return 0;\n        }\n\n        case TCP_PACKET_ONION_RESPONSE: {\n            conn->onion_callback(conn->onion_callback_object, data + 1, length - 1);\n            return 0;\n        }\n\n        default: {\n            if (data[0] < NUM_RESERVED_PORTS)\n                return -1;\n\n            uint8_t con_id = data[0] - NUM_RESERVED_PORTS;\n\n            if (conn->data_callback)\n                conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1);\n        }\n    }\n\n    return 0;\n}\n\nstatic int do_confirmed_TCP(TCP_Client_Connection *conn)\n{\n    send_pending_data(conn);\n    send_ping_response(conn);\n    send_ping_request(conn);\n\n    uint8_t packet[MAX_PACKET_SIZE];\n    int len;\n\n    if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) {\n        uint64_t ping_id = random_64b();\n\n        if (!ping_id)\n            ++ping_id;\n\n        conn->ping_request_id = conn->ping_id = ping_id;\n        send_ping_request(conn);\n        conn->last_pinged = unix_time();\n    }\n\n    if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) {\n        conn->status = TCP_CLIENT_DISCONNECTED;\n        return 0;\n    }\n\n    while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key,\n                  conn->recv_nonce, packet, sizeof(packet)))) {\n        if (len == -1) {\n            conn->status = TCP_CLIENT_DISCONNECTED;\n            break;\n        }\n\n        if (handle_TCP_packet(conn, packet, len) == -1) {\n            conn->status = TCP_CLIENT_DISCONNECTED;\n            break;\n        }\n    }\n\n    return 0;\n}\n\n/* Run the TCP connection\n */\nvoid do_TCP_connection(TCP_Client_Connection *TCP_connection)\n{\n    unix_time_update();\n\n    if (TCP_connection->status == TCP_CLIENT_DISCONNECTED) {\n        return;\n    }\n\n    if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) {\n        if (send_pending_data(TCP_connection) == 0) {\n            int ret = proxy_http_read_connection_response(TCP_connection);\n\n            if (ret == -1) {\n                TCP_connection->kill_at = 0;\n                TCP_connection->status = TCP_CLIENT_DISCONNECTED;\n            }\n\n            if (ret == 1) {\n                generate_handshake(TCP_connection);\n                TCP_connection->status = TCP_CLIENT_CONNECTING;\n            }\n        }\n    }\n\n    if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) {\n        if (send_pending_data(TCP_connection) == 0) {\n            int ret = socks5_read_handshake_response(TCP_connection);\n\n            if (ret == -1) {\n                TCP_connection->kill_at = 0;\n                TCP_connection->status = TCP_CLIENT_DISCONNECTED;\n            }\n\n            if (ret == 1) {\n                proxy_socks5_generate_connection_request(TCP_connection);\n                TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED;\n            }\n        }\n    }\n\n    if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) {\n        if (send_pending_data(TCP_connection) == 0) {\n            int ret = proxy_socks5_read_connection_response(TCP_connection);\n\n            if (ret == -1) {\n                TCP_connection->kill_at = 0;\n                TCP_connection->status = TCP_CLIENT_DISCONNECTED;\n            }\n\n            if (ret == 1) {\n                generate_handshake(TCP_connection);\n                TCP_connection->status = TCP_CLIENT_CONNECTING;\n            }\n        }\n    }\n\n    if (TCP_connection->status == TCP_CLIENT_CONNECTING) {\n        if (send_pending_data(TCP_connection) == 0) {\n            TCP_connection->status = TCP_CLIENT_UNCONFIRMED;\n        }\n    }\n\n    if (TCP_connection->status == TCP_CLIENT_UNCONFIRMED) {\n        uint8_t data[TCP_SERVER_HANDSHAKE_SIZE];\n        int len = read_TCP_packet(TCP_connection->sock, data, sizeof(data));\n\n        if (sizeof(data) == len) {\n            if (handle_handshake(TCP_connection, data) == 0) {\n                TCP_connection->kill_at = ~0;\n                TCP_connection->status = TCP_CLIENT_CONFIRMED;\n            } else {\n                TCP_connection->kill_at = 0;\n                TCP_connection->status = TCP_CLIENT_DISCONNECTED;\n            }\n        }\n    }\n\n    if (TCP_connection->status == TCP_CLIENT_CONFIRMED) {\n        do_confirmed_TCP(TCP_connection);\n    }\n\n    if (TCP_connection->kill_at <= unix_time()) {\n        TCP_connection->status = TCP_CLIENT_DISCONNECTED;\n    }\n}\n\n/* Kill the TCP connection\n */\nvoid kill_TCP_connection(TCP_Client_Connection *TCP_connection)\n{\n    if (TCP_connection == NULL)\n        return;\n\n    wipe_priority_list(TCP_connection->priority_queue_start);\n    kill_sock(TCP_connection->sock);\n    sodium_memzero(TCP_connection, sizeof(TCP_Client_Connection));\n    free(TCP_connection);\n}\n"
  },
  {
    "path": "toxcore/TCP_client.h",
    "content": "/*\n* TCP_client.h -- Implementation of the TCP relay client part of Tox.\n*\n*  Copyright (C) 2014 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n\n#ifndef TCP_CLIENT_H\n#define TCP_CLIENT_H\n\n#include \"crypto_core.h\"\n#include \"TCP_server.h\"\n\n#define TCP_CONNECTION_TIMEOUT 10\n\ntypedef enum {\n    TCP_PROXY_NONE,\n    TCP_PROXY_HTTP,\n    TCP_PROXY_SOCKS5\n} TCP_PROXY_TYPE;\n\ntypedef struct {\n    IP_Port ip_port;\n    uint8_t proxy_type; // a value from TCP_PROXY_TYPE\n} TCP_Proxy_Info;\n\nenum {\n    TCP_CLIENT_NO_STATUS,\n    TCP_CLIENT_PROXY_HTTP_CONNECTING,\n    TCP_CLIENT_PROXY_SOCKS5_CONNECTING,\n    TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED,\n    TCP_CLIENT_CONNECTING,\n    TCP_CLIENT_UNCONFIRMED,\n    TCP_CLIENT_CONFIRMED,\n    TCP_CLIENT_DISCONNECTED,\n};\ntypedef struct  {\n    uint8_t status;\n    sock_t  sock;\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES]; /* our public key */\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* public key of the server */\n    IP_Port ip_port; /* The ip and port of the server */\n    TCP_Proxy_Info proxy_info;\n    uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */\n    uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    uint16_t next_packet_length;\n\n    uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];\n\n    uint8_t last_packet[2 + MAX_PACKET_SIZE];\n    uint16_t last_packet_length;\n    uint16_t last_packet_sent;\n\n    TCP_Priority_List *priority_queue_start, *priority_queue_end;\n\n    uint64_t kill_at;\n\n    uint64_t last_pinged;\n    uint64_t ping_id;\n\n    uint64_t ping_response_id;\n    uint64_t ping_request_id;\n\n    struct {\n        uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */\n        uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n        uint32_t number;\n    } connections[NUM_CLIENT_CONNECTIONS];\n    int (*response_callback)(void *object, uint8_t connection_id, const uint8_t *public_key);\n    void *response_callback_object;\n    int (*status_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t status);\n    void *status_callback_object;\n    int (*data_callback)(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length);\n    void *data_callback_object;\n    int (*oob_data_callback)(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length);\n    void *oob_data_callback_object;\n\n    int (*onion_callback)(void *object, const uint8_t *data, uint16_t length);\n    void *onion_callback_object;\n\n    /* Can be used by user. */\n    void *custom_object;\n    uint32_t custom_uint;\n} TCP_Client_Connection;\n\n/* Create new TCP connection to ip_port/public_key\n */\nTCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key,\n        const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info);\n\n/* Run the TCP connection\n */\nvoid do_TCP_connection(TCP_Client_Connection *TCP_connection);\n\n/* Kill the TCP connection\n */\nvoid kill_TCP_connection(TCP_Client_Connection *TCP_connection);\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nint send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length);\nvoid onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, const uint8_t *data,\n                            uint16_t length), void *object);\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nint send_routing_request(TCP_Client_Connection *con, uint8_t *public_key);\nvoid routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id,\n                              const uint8_t *public_key), void *object);\nvoid routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number,\n                            uint8_t connection_id, uint8_t status), void *object);\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nint send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id);\n\n/* Set the number that will be used as an argument in the callbacks related to con_id.\n *\n * When not set by this function, the number is ~0.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number);\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure.\n */\nint send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length);\nvoid routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number,\n                          uint8_t connection_id, const uint8_t *data, uint16_t length), void *object);\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure.\n */\nint send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length);\nvoid oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, const uint8_t *public_key,\n                      const uint8_t *data, uint16_t length), void *object);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/TCP_connection.c",
    "content": "/* TCP_connection.c\n *\n * Handles TCP relay connections between two Tox clients.\n *\n *  Copyright (C) 2015 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"TCP_connection.h\"\n#include \"util.h\"\n\n/* Set the size of the array to num.\n *\n *  return -1 if realloc fails.\n *  return 0 if it succeeds.\n */\n#define realloc_tox_array(array, element_size, num, temp_pointer) (num ? (temp_pointer = realloc(array, ((num) * (element_size))), temp_pointer ? (array = temp_pointer, 0) : (-1) ) : (free(array), array = NULL, 0))\n\n\n/* return 1 if the connections_number is not valid.\n * return 0 if the connections_number is valid.\n */\nstatic _Bool connections_number_not_valid(const TCP_Connections *tcp_c, int connections_number)\n{\n    if ((unsigned int)connections_number >= tcp_c->connections_length)\n        return 1;\n\n    if (tcp_c->connections == NULL)\n        return 1;\n\n    if (tcp_c->connections[connections_number].status == TCP_CONN_NONE)\n        return 1;\n\n    return 0;\n}\n\n/* return 1 if the tcp_connections_number is not valid.\n * return 0 if the tcp_connections_number is valid.\n */\nstatic _Bool tcp_connections_number_not_valid(const TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    if ((unsigned int)tcp_connections_number >= tcp_c->tcp_connections_length)\n        return 1;\n\n    if (tcp_c->tcp_connections == NULL)\n        return 1;\n\n    if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_NONE)\n        return 1;\n\n    return 0;\n}\n\n/* Create a new empty connection.\n *\n * return -1 on failure.\n * return connections_number on success.\n */\nstatic int create_connection(TCP_Connections *tcp_c)\n{\n    uint32_t i;\n\n    for (i = 0; i < tcp_c->connections_length; ++i) {\n        if (tcp_c->connections[i].status == TCP_CONN_NONE)\n            return i;\n    }\n\n    int id = -1;\n\n    TCP_Connection_to *temp_pointer;\n\n    if (realloc_tox_array(tcp_c->connections, sizeof(TCP_Connection_to), tcp_c->connections_length + 1,\n                          temp_pointer) == 0) {\n        id = tcp_c->connections_length;\n        ++tcp_c->connections_length;\n        memset(&(tcp_c->connections[id]), 0, sizeof(TCP_Connection_to));\n    }\n\n    return id;\n}\n\n/* Create a new empty tcp connection.\n *\n * return -1 on failure.\n * return tcp_connections_number on success.\n */\nstatic int create_tcp_connection(TCP_Connections *tcp_c)\n{\n    uint32_t i;\n\n    for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n        if (tcp_c->tcp_connections[i].status == TCP_CONN_NONE)\n            return i;\n    }\n\n    int id = -1;\n\n    TCP_con *temp_pointer;\n\n    if (realloc_tox_array(tcp_c->tcp_connections, sizeof(TCP_con), tcp_c->tcp_connections_length + 1, temp_pointer) == 0) {\n        id = tcp_c->tcp_connections_length;\n        ++tcp_c->tcp_connections_length;\n        memset(&(tcp_c->tcp_connections[id]), 0, sizeof(TCP_con));\n    }\n\n    return id;\n}\n\n/* Wipe a connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int wipe_connection(TCP_Connections *tcp_c, int connections_number)\n{\n    if (connections_number_not_valid(tcp_c, connections_number))\n        return -1;\n\n    uint32_t i;\n    memset(&(tcp_c->connections[connections_number]), 0 , sizeof(TCP_Connection_to));\n\n    for (i = tcp_c->connections_length; i != 0; --i) {\n        if (tcp_c->connections[i - 1].status != TCP_CONN_NONE)\n            break;\n    }\n\n    if (tcp_c->connections_length != i) {\n        tcp_c->connections_length = i;\n        TCP_Connection_to *temp_pointer;\n        realloc_tox_array(tcp_c->connections, sizeof(TCP_Connection_to), tcp_c->connections_length, temp_pointer);\n    }\n\n    return 0;\n}\n\n/* Wipe a connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int wipe_tcp_connection(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number))\n        return -1;\n\n    uint32_t i;\n    memset(&(tcp_c->tcp_connections[tcp_connections_number]), 0 , sizeof(TCP_con));\n\n    for (i = tcp_c->tcp_connections_length; i != 0; --i) {\n        if (tcp_c->tcp_connections[i - 1].status != TCP_CONN_NONE)\n            break;\n    }\n\n    if (tcp_c->tcp_connections_length != i) {\n        tcp_c->tcp_connections_length = i;\n        TCP_con *temp_pointer;\n        realloc_tox_array(tcp_c->tcp_connections, sizeof(TCP_con), tcp_c->tcp_connections_length, temp_pointer);\n    }\n\n    return 0;\n}\n\nstatic TCP_Connection_to *get_connection(const TCP_Connections *tcp_c, int connections_number)\n{\n    if (connections_number_not_valid(tcp_c, connections_number))\n        return 0;\n\n    return &tcp_c->connections[connections_number];\n}\n\nstatic TCP_con *get_tcp_connection(const TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number))\n        return 0;\n\n    return &tcp_c->tcp_connections[tcp_connections_number];\n}\n\n/* Send a packet to the TCP connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, const uint8_t *packet, uint16_t length)\n{\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (!con_to) {\n        return -1;\n    }\n\n    //TODO: detect and kill bad relays.\n    //TODO: thread safety?\n    unsigned int i;\n    int ret = -1;\n\n    _Bool limit_reached = 0;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        uint32_t tcp_con_num = con_to->connections[i].tcp_connection;\n        uint8_t status = con_to->connections[i].status;\n        uint8_t connection_id = con_to->connections[i].connection_id;\n\n        if (tcp_con_num && status == TCP_CONNECTIONS_STATUS_ONLINE) {\n            tcp_con_num -= 1;\n            TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num);\n\n            if (!tcp_con) {\n                continue;\n            }\n\n            ret = send_data(tcp_con->connection, connection_id, packet, length);\n\n            if (ret == 0) {\n                limit_reached = 1;\n            }\n\n            if (ret == 1) {\n                break;\n            }\n        }\n    }\n\n    if (ret == 1) {\n        return 0;\n    } else if (!limit_reached) {\n        ret = 0;\n\n        /* Send oob packets to all relays tied to the connection. */\n        for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n            uint32_t tcp_con_num = con_to->connections[i].tcp_connection;\n            uint8_t status = con_to->connections[i].status;\n\n            if (tcp_con_num && status == TCP_CONNECTIONS_STATUS_REGISTERED) {\n                tcp_con_num -= 1;\n                TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num);\n\n                if (!tcp_con) {\n                    continue;\n                }\n\n                if (send_oob_packet(tcp_con->connection, con_to->public_key, packet, length) == 1) {\n                    ret += 1;\n                }\n            }\n        }\n\n        if (ret >= 1) {\n            return 0;\n        } else {\n            return -1;\n        }\n    } else {\n        return -1;\n    }\n}\n\n/* Return a random TCP connection number for use in send_tcp_onion_request.\n *\n * TODO: This number is just the index of an array that the elements can\n * change without warning.\n *\n * return TCP connection number on success.\n * return -1 on failure.\n */\nint get_random_tcp_onion_conn_number(TCP_Connections *tcp_c)\n{\n    unsigned int i, r = rand();\n\n    for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n        unsigned int index = ((i + r) % tcp_c->tcp_connections_length);\n\n        if (tcp_c->tcp_connections[index].onion && tcp_c->tcp_connections[index].status == TCP_CONN_CONNECTED) {\n            return index;\n        }\n    }\n\n    return -1;\n}\n\n/* Send an onion packet via the TCP relay corresponding to tcp_connections_number.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data,\n                           uint16_t length)\n{\n    if (tcp_connections_number >= tcp_c->tcp_connections_length) {\n        return -1;\n    }\n\n    if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_CONNECTED) {\n        int ret = send_onion_request(tcp_c->tcp_connections[tcp_connections_number].connection, data, length);\n\n        if (ret == 1)\n            return 0;\n    }\n\n    return -1;\n}\n\n/* Send an oob packet via the TCP relay corresponding to tcp_connections_number.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key,\n                        const uint8_t *packet, uint16_t length)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    if (tcp_con->status != TCP_CONN_CONNECTED)\n        return -1;\n\n    int ret = send_oob_packet(tcp_con->connection, public_key, packet, length);\n\n    if (ret == 1)\n        return 0;\n\n    return -1;\n}\n\n/* Set the callback for TCP data packets.\n */\nvoid set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id,\n                                        const uint8_t *data, uint16_t length), void *object)\n{\n    tcp_c->tcp_data_callback = tcp_data_callback;\n    tcp_c->tcp_data_callback_object = object;\n}\n\n/* Set the callback for TCP onion packets.\n */\nvoid set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_oob_callback)(void *object,\n        const uint8_t *public_key, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length), void *object)\n{\n    tcp_c->tcp_oob_callback = tcp_oob_callback;\n    tcp_c->tcp_oob_callback_object = object;\n}\n\n/* Set the callback for TCP oob data packets.\n */\nvoid set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_onion_callback)(void *object,\n        const uint8_t *data, uint16_t length), void *object)\n{\n    tcp_c->tcp_onion_callback = tcp_onion_callback;\n    tcp_c->tcp_onion_callback_object = object;\n}\n\n\n/* Find the TCP connection with public_key.\n *\n * return connections_number on success.\n * return -1 on failure.\n */\nstatic int find_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key)\n{\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->connections_length; ++i) {\n        TCP_Connection_to *con_to = get_connection(tcp_c, i);\n\n        if (con_to) {\n            if (public_key_cmp(con_to->public_key, public_key) == 0) {\n                return i;\n            }\n        }\n    }\n\n    return -1;\n}\n\n/* Find the TCP connection to a relay with relay_pk.\n *\n * return connections_number on success.\n * return -1 on failure.\n */\nstatic int find_tcp_connection_relay(TCP_Connections *tcp_c, const uint8_t *relay_pk)\n{\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n        TCP_con *tcp_con = get_tcp_connection(tcp_c, i);\n\n        if (tcp_con) {\n            if (tcp_con->status == TCP_CONN_SLEEPING) {\n                if (public_key_cmp(tcp_con->relay_pk, relay_pk) == 0) {\n                    return i;\n                }\n            } else {\n                if (public_key_cmp(tcp_con->connection->public_key, relay_pk) == 0) {\n                    return i;\n                }\n            }\n        }\n    }\n\n    return -1;\n}\n\n/* Create a new TCP connection to public_key.\n *\n * public_key must be the counterpart to the secret key that the other peer used with new_tcp_connections().\n *\n * id is the id in the callbacks for that connection.\n *\n * return connections_number on success.\n * return -1 on failure.\n */\nint new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id)\n{\n    if (find_tcp_connection_to(tcp_c, public_key) != -1)\n        return -1;\n\n    int connections_number = create_connection(tcp_c);\n\n    if (connections_number == -1)\n        return -1;\n\n    TCP_Connection_to *con_to = &tcp_c->connections[connections_number];\n\n    con_to->status = TCP_CONN_VALID;\n    memcpy(con_to->public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    con_to->id = id;\n\n    return connections_number;\n}\n\n/* return 0 on success.\n * return -1 on failure.\n */\nint kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number)\n{\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (!con_to)\n        return -1;\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        if (con_to->connections[i].tcp_connection) {\n            unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;\n            TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n            if (!tcp_con)\n                continue;\n\n            if (tcp_con->status == TCP_CONN_CONNECTED) {\n                send_disconnect_request(tcp_con->connection, con_to->connections[i].connection_id);\n            }\n\n            if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {\n                --tcp_con->lock_count;\n\n                if (con_to->status == TCP_CONN_SLEEPING) {\n                    --tcp_con->sleep_count;\n                }\n            }\n        }\n    }\n\n    return wipe_connection(tcp_c, connections_number);\n}\n\n/* Set connection status.\n *\n * status of 1 means we are using the connection.\n * status of 0 means we are not using it.\n *\n * Unused tcp connections will be disconnected from but kept in case they are needed.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, _Bool status)\n{\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (!con_to)\n        return -1;\n\n    if (status) {\n        /* Conection is unsleeping. */\n        if (con_to->status != TCP_CONN_SLEEPING)\n            return -1;\n\n        unsigned int i;\n\n        for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n            if (con_to->connections[i].tcp_connection) {\n                unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;\n                TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n                if (!tcp_con)\n                    continue;\n\n                if (tcp_con->status == TCP_CONN_SLEEPING) {\n                    tcp_con->unsleep = 1;\n                }\n            }\n        }\n\n        con_to->status = TCP_CONN_VALID;\n        return 0;\n    } else {\n        /* Conection is going to sleep. */\n        if (con_to->status != TCP_CONN_VALID)\n            return -1;\n\n        unsigned int i;\n\n        for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n            if (con_to->connections[i].tcp_connection) {\n                unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1;\n                TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n                if (!tcp_con)\n                    continue;\n\n                if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {\n                    ++tcp_con->sleep_count;\n                }\n            }\n        }\n\n        con_to->status = TCP_CONN_SLEEPING;\n        return 0;\n    }\n}\n\nstatic _Bool tcp_connection_in_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number)\n{\n    unsigned int i;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\n/* return index on success.\n * return -1 on failure.\n */\nstatic int add_tcp_connection_to_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number)\n{\n    unsigned int i;\n\n    if (tcp_connection_in_conn(con_to, tcp_connections_number))\n        return -1;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        if (con_to->connections[i].tcp_connection == 0) {\n            con_to->connections[i].tcp_connection = tcp_connections_number + 1;\n            con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE;\n            con_to->connections[i].connection_id = 0;\n            return i;\n        }\n    }\n\n    return -1;\n}\n\n/* return index on success.\n * return -1 on failure.\n */\nstatic int rm_tcp_connection_from_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number)\n{\n    unsigned int i;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {\n            con_to->connections[i].tcp_connection = 0;\n            con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE;\n            con_to->connections[i].connection_id = 0;\n            return i;\n        }\n    }\n\n    return -1;\n}\n\n/* return number of online connections on success.\n * return -1 on failure.\n */\nstatic unsigned int online_tcp_connection_from_conn(TCP_Connection_to *con_to)\n{\n    unsigned int i, count = 0;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        if (con_to->connections[i].tcp_connection) {\n            if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) {\n                ++count;\n            }\n        }\n    }\n\n    return count;\n}\n\n/* return index on success.\n * return -1 on failure.\n */\nstatic int set_tcp_connection_status(TCP_Connection_to *con_to, unsigned int tcp_connections_number,\n                                     unsigned int status, uint8_t connection_id)\n{\n    unsigned int i;\n\n    for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) {\n        if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) {\n\n            if (con_to->connections[i].status == status) {\n                return -1;\n            }\n\n            con_to->connections[i].status = status;\n            con_to->connections[i].connection_id = connection_id;\n            return i;\n        }\n    }\n\n    return -1;\n}\n\n/* Kill a TCP relay connection.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nstatic int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->connections_length; ++i) {\n        TCP_Connection_to *con_to = get_connection(tcp_c, i);\n\n        if (con_to) {\n            rm_tcp_connection_from_conn(con_to, tcp_connections_number);\n        }\n    }\n\n    if (tcp_con->onion) {\n        --tcp_c->onion_num_conns;\n    }\n\n    kill_TCP_connection(tcp_con->connection);\n\n    return wipe_tcp_connection(tcp_c, tcp_connections_number);\n}\n\nstatic int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    if (tcp_con->status == TCP_CONN_SLEEPING)\n        return -1;\n\n    IP_Port ip_port = tcp_con->connection->ip_port;\n    uint8_t relay_pk[crypto_box_PUBLICKEYBYTES];\n    memcpy(relay_pk, tcp_con->connection->public_key, crypto_box_PUBLICKEYBYTES);\n    kill_TCP_connection(tcp_con->connection);\n    tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key,\n                          &tcp_c->proxy_info);\n\n    if (!tcp_con->connection) {\n        kill_tcp_relay_connection(tcp_c, tcp_connections_number);\n        return -1;\n    }\n\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->connections_length; ++i) {\n        TCP_Connection_to *con_to = get_connection(tcp_c, i);\n\n        if (con_to) {\n            set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0);\n        }\n    }\n\n    if (tcp_con->onion) {\n        --tcp_c->onion_num_conns;\n        tcp_con->onion = 0;\n    }\n\n    tcp_con->lock_count = 0;\n    tcp_con->sleep_count = 0;\n    tcp_con->connected_time = 0;\n    tcp_con->status = TCP_CONN_VALID;\n    tcp_con->unsleep = 0;\n\n    return 0;\n}\n\nstatic int sleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    if (tcp_con->status != TCP_CONN_CONNECTED)\n        return -1;\n\n    if (tcp_con->lock_count != tcp_con->sleep_count)\n        return -1;\n\n    tcp_con->ip_port = tcp_con->connection->ip_port;\n    memcpy(tcp_con->relay_pk, tcp_con->connection->public_key, crypto_box_PUBLICKEYBYTES);\n\n    kill_TCP_connection(tcp_con->connection);\n    tcp_con->connection = NULL;\n\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->connections_length; ++i) {\n        TCP_Connection_to *con_to = get_connection(tcp_c, i);\n\n        if (con_to) {\n            set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0);\n        }\n    }\n\n    if (tcp_con->onion) {\n        --tcp_c->onion_num_conns;\n        tcp_con->onion = 0;\n    }\n\n    tcp_con->lock_count = 0;\n    tcp_con->sleep_count = 0;\n    tcp_con->connected_time = 0;\n    tcp_con->status = TCP_CONN_SLEEPING;\n    tcp_con->unsleep = 0;\n\n    return 0;\n}\n\nstatic int unsleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    if (tcp_con->status != TCP_CONN_SLEEPING)\n        return -1;\n\n    tcp_con->connection = new_TCP_connection(tcp_con->ip_port, tcp_con->relay_pk, tcp_c->self_public_key,\n                          tcp_c->self_secret_key, &tcp_c->proxy_info);\n\n    if (!tcp_con->connection) {\n        kill_tcp_relay_connection(tcp_c, tcp_connections_number);\n        return -1;\n    }\n\n    tcp_con->lock_count = 0;\n    tcp_con->sleep_count = 0;\n    tcp_con->connected_time = 0;\n    tcp_con->status = TCP_CONN_VALID;\n    tcp_con->unsleep = 0;\n    return 0;\n}\n\n/* Send a TCP routing request.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nstatic int send_tcp_relay_routing_request(TCP_Connections *tcp_c, int tcp_connections_number, uint8_t *public_key)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    if (tcp_con->status == TCP_CONN_SLEEPING)\n        return -1;\n\n    if (send_routing_request(tcp_con->connection, public_key) != 1)\n        return -1;\n\n    return 0;\n}\n\nstatic int tcp_response_callback(void *object, uint8_t connection_id, const uint8_t *public_key)\n{\n    TCP_Client_Connection *TCP_client_con = object;\n    TCP_Connections *tcp_c = TCP_client_con->custom_object;\n\n    unsigned int tcp_connections_number = TCP_client_con->custom_uint;\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    int connections_number = find_tcp_connection_to(tcp_c, public_key);\n\n    if (connections_number == -1)\n        return -1;\n\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (con_to == NULL)\n        return -1;\n\n    if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1)\n        return -1;\n\n    set_tcp_connection_number(tcp_con->connection, connection_id, connections_number);\n\n    return 0;\n}\n\nstatic int tcp_status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status)\n{\n    TCP_Client_Connection *TCP_client_con = object;\n    TCP_Connections *tcp_c = TCP_client_con->custom_object;\n\n    unsigned int tcp_connections_number = TCP_client_con->custom_uint;\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n    TCP_Connection_to *con_to = get_connection(tcp_c, number);\n\n    if (!con_to || !tcp_con)\n        return -1;\n\n    if (status == 1) {\n        if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1)\n            return -1;\n\n        --tcp_con->lock_count;\n\n        if (con_to->status == TCP_CONN_SLEEPING) {\n            --tcp_con->sleep_count;\n        }\n    } else if (status == 2) {\n        if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_ONLINE, connection_id) == -1)\n            return -1;\n\n        ++tcp_con->lock_count;\n\n        if (con_to->status == TCP_CONN_SLEEPING) {\n            ++tcp_con->sleep_count;\n        }\n    }\n\n    return 0;\n}\n\nstatic int tcp_data_callback(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length)\n{\n\n    if (length == 0)\n        return -1;\n\n    TCP_Client_Connection *TCP_client_con = object;\n    TCP_Connections *tcp_c = TCP_client_con->custom_object;\n\n    unsigned int tcp_connections_number = TCP_client_con->custom_uint;\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    TCP_Connection_to *con_to = get_connection(tcp_c, number);\n\n    if (!con_to)\n        return -1;\n\n    if (tcp_c->tcp_data_callback)\n        tcp_c->tcp_data_callback(tcp_c->tcp_data_callback_object, con_to->id, data, length);\n\n    return 0;\n}\n\nstatic int tcp_oob_callback(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length)\n{\n    if (length == 0)\n        return -1;\n\n    TCP_Client_Connection *TCP_client_con = object;\n    TCP_Connections *tcp_c = TCP_client_con->custom_object;\n\n    unsigned int tcp_connections_number = TCP_client_con->custom_uint;\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    /* TODO: optimize */\n    int connections_number = find_tcp_connection_to(tcp_c, public_key);\n\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (con_to && tcp_connection_in_conn(con_to, tcp_connections_number)) {\n        return tcp_data_callback(object, connections_number, 0, data, length);\n    } else {\n        if (tcp_c->tcp_oob_callback)\n            tcp_c->tcp_oob_callback(tcp_c->tcp_oob_callback_object, public_key, tcp_connections_number, data, length);\n    }\n\n    return 0;\n}\n\nstatic int tcp_onion_callback(void *object, const uint8_t *data, uint16_t length)\n{\n    TCP_Connections *tcp_c = object;\n\n    if (tcp_c->tcp_onion_callback)\n        tcp_c->tcp_onion_callback(tcp_c->tcp_onion_callback_object, data, length);\n\n    return 0;\n}\n\n/* Set callbacks for the TCP relay connection.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nstatic int tcp_relay_set_callbacks(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    TCP_Client_Connection *con = tcp_con->connection;\n\n    con->custom_object = tcp_c;\n    con->custom_uint = tcp_connections_number;\n    onion_response_handler(con, &tcp_onion_callback, tcp_c);\n    routing_response_handler(con, &tcp_response_callback, con);\n    routing_status_handler(con, &tcp_status_callback, con);\n    routing_data_handler(con, &tcp_data_callback, con);\n    oob_data_handler(con, &tcp_oob_callback, con);\n\n    return 0;\n}\n\nstatic int tcp_relay_on_online(TCP_Connections *tcp_c, int tcp_connections_number)\n{\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    unsigned int i, sent = 0;\n\n    for (i = 0; i < tcp_c->connections_length; ++i) {\n        TCP_Connection_to *con_to = get_connection(tcp_c, i);\n\n        if (con_to) {\n            if (tcp_connection_in_conn(con_to, tcp_connections_number)) {\n                if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) {\n                    ++sent;\n                }\n            }\n        }\n    }\n\n    tcp_relay_set_callbacks(tcp_c, tcp_connections_number);\n    tcp_con->status = TCP_CONN_CONNECTED;\n\n    /* If this connection isn't used by any connection, we don't need to wait for them to come online. */\n    if (sent) {\n        tcp_con->connected_time = unix_time();\n    } else {\n        tcp_con->connected_time = 0;\n    }\n\n    if (tcp_c->onion_status && tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) {\n        tcp_con->onion = 1;\n        ++tcp_c->onion_num_conns;\n    }\n\n    return 0;\n}\n\nstatic int add_tcp_relay_instance(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk)\n{\n    if (ip_port.ip.family == TCP_INET) {\n        ip_port.ip.family = AF_INET;\n    } else if (ip_port.ip.family == TCP_INET6) {\n        ip_port.ip.family = AF_INET6;\n    }\n\n    if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6)\n        return -1;\n\n    int tcp_connections_number = create_tcp_connection(tcp_c);\n\n    if (tcp_connections_number == -1)\n        return -1;\n\n    TCP_con *tcp_con = &tcp_c->tcp_connections[tcp_connections_number];\n\n\n    tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key,\n                          &tcp_c->proxy_info);\n\n    if (!tcp_con->connection)\n        return -1;\n\n    tcp_con->status = TCP_CONN_VALID;\n\n    return tcp_connections_number;\n}\n\n/* Add a TCP relay to the TCP_Connections instance.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint add_tcp_relay_global(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk)\n{\n    int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk);\n\n    if (tcp_connections_number != -1)\n        return -1;\n\n    if (add_tcp_relay_instance(tcp_c, ip_port, relay_pk) == -1)\n        return -1;\n\n    return 0;\n}\n\n/* Add a TCP relay tied to a connection.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_number, unsigned int tcp_connections_number)\n{\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (!con_to)\n        return -1;\n\n    TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n    if (!tcp_con)\n        return -1;\n\n    if (con_to->status != TCP_CONN_SLEEPING && tcp_con->status == TCP_CONN_SLEEPING) {\n        tcp_con->unsleep = 1;\n    }\n\n    if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1)\n        return -1;\n\n    if (tcp_con->status == TCP_CONN_CONNECTED) {\n        if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) {\n            tcp_con->connected_time = unix_time();\n        }\n    }\n\n    return 0;\n}\n\n/* Add a TCP relay tied to a connection.\n *\n * This should be called with the same relay by two peers who want to create a TCP connection with each other.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk)\n{\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (!con_to)\n        return -1;\n\n    int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk);\n\n    if (tcp_connections_number != -1) {\n        return add_tcp_number_relay_connection(tcp_c, connections_number, tcp_connections_number);\n    } else {\n        if (online_tcp_connection_from_conn(con_to) >= RECOMMENDED_FRIEND_TCP_CONNECTIONS) {\n            return -1;\n        }\n\n        int tcp_connections_number = add_tcp_relay_instance(tcp_c, ip_port, relay_pk);\n\n        TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number);\n\n        if (!tcp_con)\n            return -1;\n\n        if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) {\n            return -1;\n        }\n\n        return 0;\n    }\n}\n\n/* return number of online tcp relays tied to the connection on success.\n * return 0 on failure.\n */\nunsigned int tcp_connection_to_online_tcp_relays(TCP_Connections *tcp_c, int connections_number)\n{\n    TCP_Connection_to *con_to = get_connection(tcp_c, connections_number);\n\n    if (!con_to)\n        return 0;\n\n    return online_tcp_connection_from_conn(con_to);\n}\n\n/* Copy a maximum of max_num TCP relays we are connected to to tcp_relays.\n * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.\n *\n * return number of relays copied to tcp_relays on success.\n * return 0 on failure.\n */\nunsigned int tcp_copy_connected_relays(TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num)\n{\n    unsigned int i, copied = 0, r = rand();\n\n    for (i = 0; (i < tcp_c->tcp_connections_length) && (copied < max_num); ++i) {\n        TCP_con *tcp_con = get_tcp_connection(tcp_c, (i + r) % tcp_c->tcp_connections_length);\n\n        if (!tcp_con) {\n            continue;\n        }\n\n        if (tcp_con->status == TCP_CONN_CONNECTED) {\n            memcpy(tcp_relays[copied].public_key, tcp_con->connection->public_key, crypto_box_PUBLICKEYBYTES);\n            tcp_relays[copied].ip_port = tcp_con->connection->ip_port;\n\n            if (tcp_relays[copied].ip_port.ip.family == AF_INET) {\n                tcp_relays[copied].ip_port.ip.family = TCP_INET;\n            } else if (tcp_relays[copied].ip_port.ip.family == AF_INET6) {\n                tcp_relays[copied].ip_port.ip.family = TCP_INET6;\n            }\n\n            ++copied;\n        }\n    }\n\n    return copied;\n}\n\n/* Set if we want TCP_connection to allocate some connection for onion use.\n *\n * If status is 1, allocate some connections. if status is 0, don't.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint set_tcp_onion_status(TCP_Connections *tcp_c, _Bool status)\n{\n    if (tcp_c->onion_status == status)\n        return -1;\n\n    if (status) {\n        unsigned int i;\n\n        for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n            TCP_con *tcp_con = get_tcp_connection(tcp_c, i);\n\n            if (tcp_con) {\n                if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion) {\n                    ++tcp_c->onion_num_conns;\n                    tcp_con->onion = 1;\n                }\n            }\n\n            if (tcp_c->onion_num_conns >= NUM_ONION_TCP_CONNECTIONS)\n                break;\n        }\n\n        if (tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) {\n            unsigned int wakeup = NUM_ONION_TCP_CONNECTIONS - tcp_c->onion_num_conns;\n\n            for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n                TCP_con *tcp_con = get_tcp_connection(tcp_c, i);\n\n                if (tcp_con) {\n                    if (tcp_con->status == TCP_CONN_SLEEPING) {\n                        tcp_con->unsleep = 1;\n                    }\n                }\n\n                if (!wakeup)\n                    break;\n            }\n        }\n\n        tcp_c->onion_status = 1;\n    } else {\n        unsigned int i;\n\n        for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n            TCP_con *tcp_con = get_tcp_connection(tcp_c, i);\n\n            if (tcp_con) {\n                if (tcp_con->onion) {\n                    --tcp_c->onion_num_conns;\n                    tcp_con->onion = 0;\n                }\n            }\n        }\n\n        tcp_c->onion_status = 0;\n    }\n\n    return 0;\n}\n\n/* Returns a new TCP_Connections object associated with the secret_key.\n *\n * In order for others to connect to this instance new_tcp_connection_to() must be called with the\n * public_key associated with secret_key.\n *\n * Returns NULL on failure.\n */\nTCP_Connections *new_tcp_connections(const uint8_t *secret_key, TCP_Proxy_Info *proxy_info)\n{\n    if (secret_key == NULL)\n        return NULL;\n\n    TCP_Connections *temp = calloc(1, sizeof(TCP_Connections));\n\n    if (temp == NULL)\n        return NULL;\n\n    memcpy(temp->self_secret_key, secret_key, crypto_box_SECRETKEYBYTES);\n    crypto_scalarmult_curve25519_base(temp->self_public_key, temp->self_secret_key);\n    temp->proxy_info = *proxy_info;\n\n    return temp;\n}\n\nstatic void do_tcp_conns(TCP_Connections *tcp_c)\n{\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n        TCP_con *tcp_con = get_tcp_connection(tcp_c, i);\n\n        if (tcp_con) {\n            if (tcp_con->status != TCP_CONN_SLEEPING) {\n                do_TCP_connection(tcp_con->connection);\n\n                /* callbacks can change TCP connection address. */\n                tcp_con = get_tcp_connection(tcp_c, i);\n\n                if (tcp_con->connection->status == TCP_CLIENT_DISCONNECTED) {\n                    if (tcp_con->status == TCP_CONN_CONNECTED) {\n                        reconnect_tcp_relay_connection(tcp_c, i);\n                    } else {\n                        kill_tcp_relay_connection(tcp_c, i);\n                    }\n\n                    continue;\n                }\n\n                if (tcp_con->status == TCP_CONN_VALID && tcp_con->connection->status == TCP_CLIENT_CONFIRMED) {\n                    tcp_relay_on_online(tcp_c, i);\n                }\n\n                if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion && tcp_con->lock_count\n                        && tcp_con->lock_count == tcp_con->sleep_count\n                        && is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) {\n                    sleep_tcp_relay_connection(tcp_c, i);\n                }\n            }\n\n            if (tcp_con->status == TCP_CONN_SLEEPING && tcp_con->unsleep) {\n                unsleep_tcp_relay_connection(tcp_c, i);\n            }\n        }\n    }\n}\n\nstatic void kill_nonused_tcp(TCP_Connections *tcp_c)\n{\n    if (tcp_c->tcp_connections_length == 0)\n        return;\n\n    unsigned int i, num_online = 0, num_kill = 0, to_kill[tcp_c->tcp_connections_length];\n\n    for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n        TCP_con *tcp_con = get_tcp_connection(tcp_c, i);\n\n        if (tcp_con) {\n            if (tcp_con->status == TCP_CONN_CONNECTED) {\n                if (!tcp_con->onion && !tcp_con->lock_count && is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) {\n                    to_kill[num_kill] = i;\n                    ++num_kill;\n                }\n\n                ++num_online;\n            }\n        }\n    }\n\n    if (num_online <= RECOMMENDED_FRIEND_TCP_CONNECTIONS) {\n        return;\n    } else {\n        unsigned int n = num_online - RECOMMENDED_FRIEND_TCP_CONNECTIONS;\n\n        if (n < num_kill)\n            num_kill = n;\n    }\n\n    for (i = 0; i < num_kill; ++i) {\n        kill_tcp_relay_connection(tcp_c, to_kill[i]);\n    }\n}\n\nvoid do_tcp_connections(TCP_Connections *tcp_c)\n{\n    do_tcp_conns(tcp_c);\n    kill_nonused_tcp(tcp_c);\n}\n\nvoid kill_tcp_connections(TCP_Connections *tcp_c)\n{\n    unsigned int i;\n\n    for (i = 0; i < tcp_c->tcp_connections_length; ++i) {\n        kill_TCP_connection(tcp_c->tcp_connections[i].connection);\n    }\n\n    free(tcp_c->tcp_connections);\n    free(tcp_c->connections);\n    free(tcp_c);\n}\n\n\n"
  },
  {
    "path": "toxcore/TCP_connection.h",
    "content": "/* TCP_connection.h\n *\n * Handles TCP relay connections between two Tox clients.\n *\n *  Copyright (C) 2015 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TCP_CONNECTION_H\n#define TCP_CONNECTION_H\n\n#include \"TCP_client.h\"\n\n#define TCP_CONN_NONE 0\n#define TCP_CONN_VALID 1\n\n/* NOTE: only used by TCP_con */\n#define TCP_CONN_CONNECTED 2\n\n/* Connection is not connected but can be quickly reconnected in case it is needed. */\n#define TCP_CONN_SLEEPING 3\n\n#define TCP_CONNECTIONS_STATUS_NONE 0\n#define TCP_CONNECTIONS_STATUS_REGISTERED 1\n#define TCP_CONNECTIONS_STATUS_ONLINE 2\n\n#define MAX_FRIEND_TCP_CONNECTIONS 6\n\n/* Time until connection to friend gets killed (if it doesn't get locked withing that time) */\n#define TCP_CONNECTION_ANNOUNCE_TIMEOUT (TCP_CONNECTION_TIMEOUT)\n\n/* The amount of recommended connections for each friend\n   NOTE: Must be at most (MAX_FRIEND_TCP_CONNECTIONS / 2) */\n#define RECOMMENDED_FRIEND_TCP_CONNECTIONS (MAX_FRIEND_TCP_CONNECTIONS / 2)\n\n/* Number of TCP connections used for onion purposes. */\n#define NUM_ONION_TCP_CONNECTIONS RECOMMENDED_FRIEND_TCP_CONNECTIONS\n\ntypedef struct {\n    uint8_t status;\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */\n\n    struct {\n        uint32_t tcp_connection;\n        unsigned int status;\n        unsigned int connection_id;\n    } connections[MAX_FRIEND_TCP_CONNECTIONS];\n\n    int id; /* id used in callbacks. */\n} TCP_Connection_to;\n\ntypedef struct {\n    uint8_t status;\n    TCP_Client_Connection *connection;\n    uint64_t connected_time;\n    uint32_t lock_count;\n    uint32_t sleep_count;\n    _Bool onion;\n\n    /* Only used when connection is sleeping. */\n    IP_Port ip_port;\n    uint8_t relay_pk[crypto_box_PUBLICKEYBYTES];\n    _Bool unsleep; /* set to 1 to unsleep connection. */\n} TCP_con;\n\ntypedef struct {\n    DHT *dht;\n\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n\n    TCP_Connection_to *connections;\n    uint32_t connections_length; /* Length of connections array. */\n\n    TCP_con *tcp_connections;\n    uint32_t tcp_connections_length; /* Length of tcp_connections array. */\n\n    int (*tcp_data_callback)(void *object, int id, const uint8_t *data, uint16_t length);\n    void *tcp_data_callback_object;\n\n    int (*tcp_oob_callback)(void *object, const uint8_t *public_key, unsigned int tcp_connections_number,\n                            const uint8_t *data, uint16_t length);\n    void *tcp_oob_callback_object;\n\n    int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length);\n    void *tcp_onion_callback_object;\n\n    TCP_Proxy_Info proxy_info;\n\n    _Bool onion_status;\n    uint16_t onion_num_conns;\n} TCP_Connections;\n\n/* Send a packet to the TCP connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, const uint8_t *packet, uint16_t length);\n\n/* Return a random TCP connection number for use in send_tcp_onion_request.\n *\n * TODO: This number is just the index of an array that the elements can\n * change without warning.\n *\n * return TCP connection number on success.\n * return -1 on failure.\n */\nint get_random_tcp_onion_conn_number(TCP_Connections *tcp_c);\n\n/* Send an onion packet via the TCP relay corresponding to tcp_connections_number.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data,\n                           uint16_t length);\n\n/* Set if we want TCP_connection to allocate some connection for onion use.\n *\n * If status is 1, allocate some connections. if status is 0, don't.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint set_tcp_onion_status(TCP_Connections *tcp_c, _Bool status);\n\n/* Send an oob packet via the TCP relay corresponding to tcp_connections_number.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key,\n                        const uint8_t *packet, uint16_t length);\n\n/* Set the callback for TCP data packets.\n */\nvoid set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id,\n                                        const uint8_t *data, uint16_t length), void *object);\n\n/* Set the callback for TCP onion packets.\n */\nvoid set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_onion_callback)(void *object,\n        const uint8_t *data, uint16_t length), void *object);\n\n/* Set the callback for TCP oob data packets.\n */\nvoid set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_oob_callback)(void *object,\n        const uint8_t *public_key, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length), void *object);\n\n/* Create a new TCP connection to public_key.\n *\n * public_key must be the counterpart to the secret key that the other peer used with new_tcp_connections().\n *\n * id is the id in the callbacks for that connection.\n *\n * return connections_number on success.\n * return -1 on failure.\n */\nint new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id);\n\n/* return 0 on success.\n * return -1 on failure.\n */\nint kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number);\n\n/* Set connection status.\n *\n * status of 1 means we are using the connection.\n * status of 0 means we are not using it.\n *\n * Unused tcp connections will be disconnected from but kept in case they are needed.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, _Bool status);\n\n/* return number of online tcp relays tied to the connection on success.\n * return 0 on failure.\n */\nunsigned int tcp_connection_to_online_tcp_relays(TCP_Connections *tcp_c, int connections_number);\n\n/* Add a TCP relay tied to a connection.\n *\n * NOTE: This can only be used during the tcp_oob_callback.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_number,\n                                    unsigned int tcp_connections_number);\n\n/* Add a TCP relay tied to a connection.\n *\n * This should be called with the same relay by two peers who want to create a TCP connection with each other.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk);\n\n/* Add a TCP relay to the instance.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint add_tcp_relay_global(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk);\n\n/* Copy a maximum of max_num TCP relays we are connected to to tcp_relays.\n * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.\n *\n * return number of relays copied to tcp_relays on success.\n * return 0 on failure.\n */\nunsigned int tcp_copy_connected_relays(TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num);\n\n/* Returns a new TCP_Connections object associated with the secret_key.\n *\n * In order for others to connect to this instance new_tcp_connection_to() must be called with the\n * public_key associated with secret_key.\n *\n * Returns NULL on failure.\n */\nTCP_Connections *new_tcp_connections(const uint8_t *secret_key, TCP_Proxy_Info *proxy_info);\n\nvoid do_tcp_connections(TCP_Connections *tcp_c);\nvoid kill_tcp_connections(TCP_Connections *tcp_c);\n\n#endif\n\n"
  },
  {
    "path": "toxcore/TCP_server.c",
    "content": "/*\n* TCP_server.c -- Implementation of the TCP relay server part of Tox.\n*\n*  Copyright (C) 2014 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"TCP_server.h\"\n\n#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)\n#include <sys/ioctl.h>\n#endif\n\n#include \"util.h\"\n\n/* return 1 on success\n * return 0 on failure\n */\nstatic int bind_to_port(sock_t sock, int family, uint16_t port)\n{\n    struct sockaddr_storage addr = {0};\n    size_t addrsize;\n\n    if (family == AF_INET) {\n        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in);\n        addr4->sin_family = AF_INET;\n        addr4->sin_port = htons(port);\n    } else if (family == AF_INET6) {\n        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in6);\n        addr6->sin6_family = AF_INET6;\n        addr6->sin6_port = htons(port);\n    } else {\n        return 0;\n    }\n\n    return (bind(sock, (struct sockaddr *)&addr, addrsize) == 0);\n}\n\n/* Set the size of the connection list to numfriends.\n *\n *  return -1 if realloc fails.\n *  return 0 if it succeeds.\n */\nstatic int realloc_connection(TCP_Server *TCP_server, uint32_t num)\n{\n    if (num == 0) {\n        free(TCP_server->accepted_connection_array);\n        TCP_server->accepted_connection_array = NULL;\n        TCP_server->size_accepted_connections = 0;\n        return 0;\n    }\n\n    if (num == TCP_server->size_accepted_connections) {\n        return 0;\n    }\n\n    TCP_Secure_Connection *new_connections = realloc(TCP_server->accepted_connection_array,\n            num * sizeof(TCP_Secure_Connection));\n\n    if (new_connections == NULL)\n        return -1;\n\n    if (num > TCP_server->size_accepted_connections) {\n        uint32_t old_size = TCP_server->size_accepted_connections;\n        uint32_t size_new_entries = (num - old_size) * sizeof(TCP_Secure_Connection);\n        memset(new_connections + old_size, 0, size_new_entries);\n    }\n\n    TCP_server->accepted_connection_array = new_connections;\n    TCP_server->size_accepted_connections = num;\n    return 0;\n}\n\n/* return index corresponding to connection with peer on success\n * return -1 on failure.\n */\nstatic int get_TCP_connection_index(const TCP_Server *TCP_server, const uint8_t *public_key)\n{\n    return bs_list_find(&TCP_server->accepted_key_list, public_key);\n}\n\n\nstatic int kill_accepted(TCP_Server *TCP_server, int index);\n\n/* Add accepted TCP connection to the list.\n *\n * return index on success\n * return -1 on failure\n */\nstatic int add_accepted(TCP_Server *TCP_server, const TCP_Secure_Connection *con)\n{\n    int index = get_TCP_connection_index(TCP_server, con->public_key);\n\n    if (index != -1) { /* If an old connection to the same public key exists, kill it. */\n        kill_accepted(TCP_server, index);\n        index = -1;\n    }\n\n    if (TCP_server->size_accepted_connections == TCP_server->num_accepted_connections) {\n        if (realloc_connection(TCP_server, TCP_server->size_accepted_connections + 4) == -1)\n            return -1;\n\n        index = TCP_server->num_accepted_connections;\n    } else {\n        uint32_t i;\n\n        for (i = TCP_server->size_accepted_connections; i != 0; --i) {\n            if (TCP_server->accepted_connection_array[i - 1].status == TCP_STATUS_NO_STATUS) {\n                index = i - 1;\n                break;\n            }\n        }\n    }\n\n    if (index == -1) {\n        fprintf(stderr, \"FAIL index is -1\\n\");\n        return -1;\n    }\n\n    if (!bs_list_add(&TCP_server->accepted_key_list, con->public_key, index))\n        return -1;\n\n    memcpy(&TCP_server->accepted_connection_array[index], con, sizeof(TCP_Secure_Connection));\n    TCP_server->accepted_connection_array[index].status = TCP_STATUS_CONFIRMED;\n    ++TCP_server->num_accepted_connections;\n    TCP_server->accepted_connection_array[index].identifier = ++TCP_server->counter;\n    TCP_server->accepted_connection_array[index].last_pinged = unix_time();\n    TCP_server->accepted_connection_array[index].ping_id = 0;\n\n    return index;\n}\n\n/* Delete accepted connection from list.\n *\n * return 0 on success\n * return -1 on failure\n */\nstatic int del_accepted(TCP_Server *TCP_server, int index)\n{\n    if ((uint32_t)index >= TCP_server->size_accepted_connections)\n        return -1;\n\n    if (TCP_server->accepted_connection_array[index].status == TCP_STATUS_NO_STATUS)\n        return -1;\n\n    if (!bs_list_remove(&TCP_server->accepted_key_list, TCP_server->accepted_connection_array[index].public_key, index))\n        return -1;\n\n    wipe_priority_list(TCP_server->accepted_connection_array[index].priority_queue_start);\n    sodium_memzero(&TCP_server->accepted_connection_array[index], sizeof(TCP_Secure_Connection));\n    --TCP_server->num_accepted_connections;\n\n    if (TCP_server->num_accepted_connections == 0)\n        realloc_connection(TCP_server, 0);\n\n    return 0;\n}\n\n/* return the amount of data in the tcp recv buffer.\n * return 0 on failure.\n */\nunsigned int TCP_socket_data_recv_buffer(sock_t sock)\n{\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    unsigned long count = 0;\n    ioctlsocket(sock, FIONREAD, &count);\n#else\n    int count = 0;\n    ioctl(sock, FIONREAD, &count);\n#endif\n\n    return count;\n}\n\n/* Read the next two bytes in TCP stream then convert them to\n * length (host byte order).\n *\n * return length on success\n * return 0 if nothing has been read from socket.\n * return ~0 on failure.\n */\nuint16_t read_TCP_length(sock_t sock)\n{\n    unsigned int count = TCP_socket_data_recv_buffer(sock);\n\n    if (count >= sizeof(uint16_t)) {\n        uint16_t length;\n        int len = recv(sock, (uint8_t *)&length, sizeof(uint16_t), MSG_NOSIGNAL);\n\n        if (len != sizeof(uint16_t)) {\n            fprintf(stderr, \"FAIL recv packet\\n\");\n            return 0;\n        }\n\n        length = ntohs(length);\n\n        if (length > MAX_PACKET_SIZE) {\n            return ~0;\n        }\n\n        return length;\n    }\n\n    return 0;\n}\n\n/* Read length bytes from socket.\n *\n * return length on success\n * return -1 on failure/no data in buffer.\n */\nint read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length)\n{\n    unsigned int count = TCP_socket_data_recv_buffer(sock);\n\n    if (count >= length) {\n        int len = recv(sock, data, length, MSG_NOSIGNAL);\n\n        if (len != length) {\n            fprintf(stderr, \"FAIL recv packet\\n\");\n            return -1;\n        }\n\n        return len;\n    }\n\n    return -1;\n}\n\n/* return length of received packet on success.\n * return 0 if could not read any packet.\n * return -1 on failure (connection must be killed).\n */\nint read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, const uint8_t *shared_key,\n                                      uint8_t *recv_nonce, uint8_t *data, uint16_t max_len)\n{\n    if (*next_packet_length == 0) {\n        uint16_t len = read_TCP_length(sock);\n\n        if (len == (uint16_t)~0)\n            return -1;\n\n        if (len == 0)\n            return 0;\n\n        *next_packet_length = len;\n    }\n\n    if (max_len + crypto_box_MACBYTES < *next_packet_length)\n        return -1;\n\n    uint8_t data_encrypted[*next_packet_length];\n    int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length);\n\n    if (len_packet != *next_packet_length)\n        return 0;\n\n    *next_packet_length = 0;\n\n    int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data);\n\n    if (len + crypto_box_MACBYTES != len_packet)\n        return -1;\n\n    increment_nonce(recv_nonce);\n\n    return len;\n}\n\n/* return 0 if pending data was sent completely\n * return -1 if it wasn't\n */\nstatic int send_pending_data_nonpriority(TCP_Secure_Connection *con)\n{\n    if (con->last_packet_length == 0) {\n        return 0;\n    }\n\n    uint16_t left = con->last_packet_length - con->last_packet_sent;\n    int len = send(con->sock, con->last_packet + con->last_packet_sent, left, MSG_NOSIGNAL);\n\n    if (len <= 0)\n        return -1;\n\n    if (len == left) {\n        con->last_packet_length = 0;\n        con->last_packet_sent = 0;\n        return 0;\n    }\n\n    con->last_packet_sent += len;\n    return -1;\n\n}\n\nvoid wipe_priority_list(TCP_Priority_List *p)\n{\n    while (p) {\n        TCP_Priority_List *pp = p;\n        p = p->next;\n        free(pp);\n    }\n}\n\n/* return 0 if pending data was sent completely\n * return -1 if it wasn't\n */\nstatic int send_pending_data(TCP_Secure_Connection *con)\n{\n    /* finish sending current non-priority packet */\n    if (send_pending_data_nonpriority(con) == -1) {\n        return -1;\n    }\n\n    TCP_Priority_List *p = con->priority_queue_start;\n\n    while (p) {\n        uint16_t left = p->size - p->sent;\n        int len = send(con->sock, p->data + p->sent, left, MSG_NOSIGNAL);\n\n        if (len != left) {\n            if (len > 0) {\n                p->sent += len;\n            }\n\n            break;\n        }\n\n        TCP_Priority_List *pp = p;\n        p = p->next;\n        free(pp);\n    }\n\n    con->priority_queue_start = p;\n\n    if (!p) {\n        con->priority_queue_end = NULL;\n        return 0;\n    }\n\n    return -1;\n}\n\n/* return 0 on failure (only if malloc fails)\n * return 1 on success\n */\nstatic _Bool add_priority(TCP_Secure_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent)\n{\n    TCP_Priority_List *p = con->priority_queue_end, *new;\n    new = malloc(sizeof(TCP_Priority_List) + size);\n\n    if (!new) {\n        return 0;\n    }\n\n    new->next = NULL;\n    new->size = size;\n    new->sent = sent;\n    memcpy(new->data, packet, size);\n\n    if (p) {\n        p->next = new;\n    } else {\n        con->priority_queue_start = new;\n    }\n\n    con->priority_queue_end = new;\n    return 1;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length,\n        _Bool priority)\n{\n    if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE)\n        return -1;\n\n    _Bool sendpriority = 1;\n\n    if (send_pending_data(con) == -1) {\n        if (priority) {\n            sendpriority = 0;\n        } else {\n            return 0;\n        }\n    }\n\n    uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES];\n\n    uint16_t c_length = htons(length + crypto_box_MACBYTES);\n    memcpy(packet, &c_length, sizeof(uint16_t));\n    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));\n\n    if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))\n        return -1;\n\n    if (priority) {\n        len = sendpriority ? send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL) : 0;\n\n        if (len <= 0) {\n            len = 0;\n        }\n\n        increment_nonce(con->sent_nonce);\n\n        if ((unsigned int)len == sizeof(packet)) {\n            return 1;\n        }\n\n        return add_priority(con, packet, sizeof(packet), len);\n    }\n\n    len = send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL);\n\n    if (len <= 0)\n        return 0;\n\n    increment_nonce(con->sent_nonce);\n\n    if ((unsigned int)len == sizeof(packet))\n        return 1;\n\n    memcpy(con->last_packet, packet, sizeof(packet));\n    con->last_packet_length = sizeof(packet);\n    con->last_packet_sent = len;\n    return 1;\n}\n\n/* Kill a TCP_Secure_Connection\n */\nstatic void kill_TCP_connection(TCP_Secure_Connection *con)\n{\n    wipe_priority_list(con->priority_queue_start);\n    kill_sock(con->sock);\n    sodium_memzero(con, sizeof(TCP_Secure_Connection));\n}\n\nstatic int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number);\n\n/* Kill an accepted TCP_Secure_Connection\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int kill_accepted(TCP_Server *TCP_server, int index)\n{\n    if ((uint32_t)index >= TCP_server->size_accepted_connections)\n        return -1;\n\n    uint32_t i;\n\n    for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) {\n        rm_connection_index(TCP_server, &TCP_server->accepted_connection_array[index], i);\n    }\n\n    sock_t sock = TCP_server->accepted_connection_array[index].sock;\n\n    if (del_accepted(TCP_server, index) != 0)\n        return -1;\n\n    kill_sock(sock);\n    return 0;\n}\n\n/* return 1 if everything went well.\n * return -1 if the connection must be killed.\n */\nstatic int handle_TCP_handshake(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length,\n                                const uint8_t *self_secret_key)\n{\n    if (length != TCP_CLIENT_HANDSHAKE_SIZE)\n        return -1;\n\n    if (con->status != TCP_STATUS_CONNECTED)\n        return -1;\n\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    encrypt_precompute(data, self_secret_key, shared_key);\n    uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE];\n    int len = decrypt_data_symmetric(shared_key, data + crypto_box_PUBLICKEYBYTES,\n                                     data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain);\n\n    if (len != TCP_HANDSHAKE_PLAIN_SIZE)\n        return -1;\n\n    memcpy(con->public_key, data, crypto_box_PUBLICKEYBYTES);\n    uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];\n    uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE];\n    crypto_box_keypair(resp_plain, temp_secret_key);\n    random_nonce(con->sent_nonce);\n    memcpy(resp_plain + crypto_box_PUBLICKEYBYTES, con->sent_nonce, crypto_box_NONCEBYTES);\n    memcpy(con->recv_nonce, plain + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);\n\n    uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];\n    new_nonce(response);\n\n    len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE,\n                                 response + crypto_box_NONCEBYTES);\n\n    if (len != TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)\n        return -1;\n\n    if (TCP_SERVER_HANDSHAKE_SIZE != send(con->sock, response, TCP_SERVER_HANDSHAKE_SIZE, MSG_NOSIGNAL))\n        return -1;\n\n    encrypt_precompute(plain, temp_secret_key, con->shared_key);\n    con->status = TCP_STATUS_UNCONFIRMED;\n    return 1;\n}\n\n/* return 1 if connection handshake was handled correctly.\n * return 0 if we didn't get it yet.\n * return -1 if the connection must be killed.\n */\nstatic int read_connection_handshake(TCP_Secure_Connection *con, const uint8_t *self_secret_key)\n{\n    uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE];\n    int len = 0;\n\n    if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) {\n        return handle_TCP_handshake(con, data, len, self_secret_key);\n    }\n\n    return 0;\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int send_routing_response(TCP_Secure_Connection *con, uint8_t rpid, const uint8_t *public_key)\n{\n    uint8_t data[1 + 1 + crypto_box_PUBLICKEYBYTES];\n    data[0] = TCP_PACKET_ROUTING_RESPONSE;\n    data[1] = rpid;\n    memcpy(data + 2, public_key, crypto_box_PUBLICKEYBYTES);\n\n    return write_packet_TCP_secure_connection(con, data, sizeof(data), 1);\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int send_connect_notification(TCP_Secure_Connection *con, uint8_t id)\n{\n    uint8_t data[2] = {TCP_PACKET_CONNECTION_NOTIFICATION, id + NUM_RESERVED_PORTS};\n    return write_packet_TCP_secure_connection(con, data, sizeof(data), 1);\n}\n\n/* return 1 on success.\n * return 0 if could not send packet.\n * return -1 on failure (connection must be killed).\n */\nstatic int send_disconnect_notification(TCP_Secure_Connection *con, uint8_t id)\n{\n    uint8_t data[2] = {TCP_PACKET_DISCONNECT_NOTIFICATION, id + NUM_RESERVED_PORTS};\n    return write_packet_TCP_secure_connection(con, data, sizeof(data), 1);\n}\n\n/* return 0 on success.\n * return -1 on failure (connection must be killed).\n */\nstatic int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key)\n{\n    uint32_t i;\n    uint32_t index = ~0;\n    TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id];\n\n    /* If person tries to cennect to himself we deny the request*/\n    if (public_key_cmp(con->public_key, public_key) == 0) {\n        if (send_routing_response(con, 0, public_key) == -1)\n            return -1;\n\n        return 0;\n    }\n\n    for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) {\n        if (con->connections[i].status != 0) {\n            if (public_key_cmp(public_key, con->connections[i].public_key) == 0) {\n                if (send_routing_response(con, i + NUM_RESERVED_PORTS, public_key) == -1) {\n                    return -1;\n                } else {\n                    return 0;\n                }\n            }\n        } else if (index == (uint32_t)~0) {\n            index = i;\n        }\n    }\n\n    if (index == (uint32_t)~0) {\n        if (send_routing_response(con, 0, public_key) == -1)\n            return -1;\n\n        return 0;\n    }\n\n    int ret = send_routing_response(con, index + NUM_RESERVED_PORTS, public_key);\n\n    if (ret == 0)\n        return 0;\n\n    if (ret == -1)\n        return -1;\n\n    con->connections[index].status = 1;\n    memcpy(con->connections[index].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    int other_index = get_TCP_connection_index(TCP_server, public_key);\n\n    if (other_index != -1) {\n        uint32_t other_id = ~0;\n        TCP_Secure_Connection *other_conn = &TCP_server->accepted_connection_array[other_index];\n\n        for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) {\n            if (other_conn->connections[i].status == 1\n                    && public_key_cmp(other_conn->connections[i].public_key, con->public_key) == 0) {\n                other_id = i;\n                break;\n            }\n        }\n\n        if (other_id != (uint32_t)~0) {\n            con->connections[index].status = 2;\n            con->connections[index].index = other_index;\n            con->connections[index].other_id = other_id;\n            other_conn->connections[other_id].status = 2;\n            other_conn->connections[other_id].index = con_id;\n            other_conn->connections[other_id].other_id = index;\n            //TODO: return values?\n            send_connect_notification(con, index);\n            send_connect_notification(other_conn, other_id);\n        }\n    }\n\n    return 0;\n}\n\n/* return 0 on success.\n * return -1 on failure (connection must be killed).\n */\nstatic int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key, const uint8_t *data,\n                               uint16_t length)\n{\n    if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH)\n        return -1;\n\n    TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id];\n\n    int other_index = get_TCP_connection_index(TCP_server, public_key);\n\n    if (other_index != -1) {\n        uint8_t resp_packet[1 + crypto_box_PUBLICKEYBYTES + length];\n        resp_packet[0] = TCP_PACKET_OOB_RECV;\n        memcpy(resp_packet + 1, con->public_key, crypto_box_PUBLICKEYBYTES);\n        memcpy(resp_packet + 1 + crypto_box_PUBLICKEYBYTES, data, length);\n        write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet,\n                                           sizeof(resp_packet), 0);\n    }\n\n    return 0;\n}\n\n/* Remove connection with con_number from the connections array of con.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number)\n{\n    if (con_number >= NUM_CLIENT_CONNECTIONS)\n        return -1;\n\n    if (con->connections[con_number].status) {\n        uint32_t index = con->connections[con_number].index;\n        uint8_t other_id = con->connections[con_number].other_id;\n\n        if (con->connections[con_number].status == 2) {\n\n            if (index >= TCP_server->size_accepted_connections)\n                return -1;\n\n            TCP_server->accepted_connection_array[index].connections[other_id].other_id = 0;\n            TCP_server->accepted_connection_array[index].connections[other_id].index = 0;\n            TCP_server->accepted_connection_array[index].connections[other_id].status = 1;\n            //TODO: return values?\n            send_disconnect_notification(&TCP_server->accepted_connection_array[index], other_id);\n        }\n\n        con->connections[con_number].index = 0;\n        con->connections[con_number].other_id = 0;\n        con->connections[con_number].status = 0;\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\nstatic int handle_onion_recv_1(void *object, IP_Port dest, const uint8_t *data, uint16_t length)\n{\n    TCP_Server *TCP_server = object;\n    uint32_t index = dest.ip.ip6.uint32[0];\n\n    if (index >= TCP_server->size_accepted_connections)\n        return 1;\n\n    TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[index];\n\n    if (con->identifier != dest.ip.ip6.uint64[1])\n        return 1;\n\n    uint8_t packet[1 + length];\n    memcpy(packet + 1, data, length);\n    packet[0] = TCP_PACKET_ONION_RESPONSE;\n\n    if (write_packet_TCP_secure_connection(con, packet, sizeof(packet), 0) != 1)\n        return 1;\n\n    return 0;\n}\n\n/* return 0 on success\n * return -1 on failure\n */\nstatic int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *data, uint16_t length)\n{\n    if (length == 0)\n        return -1;\n\n    TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id];\n\n    switch (data[0]) {\n        case TCP_PACKET_ROUTING_REQUEST: {\n            if (length != 1 + crypto_box_PUBLICKEYBYTES)\n                return -1;\n\n            return handle_TCP_routing_req(TCP_server, con_id, data + 1);\n        }\n\n        case TCP_PACKET_CONNECTION_NOTIFICATION: {\n            if (length != 2)\n                return -1;\n\n            break;\n        }\n\n        case TCP_PACKET_DISCONNECT_NOTIFICATION: {\n            if (length != 2)\n                return -1;\n\n            return rm_connection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS);\n        }\n\n        case TCP_PACKET_PING: {\n            if (length != 1 + sizeof(uint64_t))\n                return -1;\n\n            uint8_t response[1 + sizeof(uint64_t)];\n            response[0] = TCP_PACKET_PONG;\n            memcpy(response + 1, data + 1, sizeof(uint64_t));\n            write_packet_TCP_secure_connection(con, response, sizeof(response), 1);\n            return 0;\n        }\n\n        case TCP_PACKET_PONG: {\n            if (length != 1 + sizeof(uint64_t))\n                return -1;\n\n            uint64_t ping_id;\n            memcpy(&ping_id, data + 1, sizeof(uint64_t));\n\n            if (ping_id) {\n                if (ping_id == con->ping_id) {\n                    con->ping_id = 0;\n                }\n\n                return 0;\n            } else {\n                return -1;\n            }\n        }\n\n        case TCP_PACKET_OOB_SEND: {\n            if (length <= 1 + crypto_box_PUBLICKEYBYTES)\n                return -1;\n\n            return handle_TCP_oob_send(TCP_server, con_id, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES,\n                                       length - (1 + crypto_box_PUBLICKEYBYTES));\n        }\n\n        case TCP_PACKET_ONION_REQUEST: {\n            if (TCP_server->onion) {\n                if (length <= 1 + crypto_box_NONCEBYTES + ONION_SEND_BASE * 2)\n                    return -1;\n\n                IP_Port source;\n                source.port = 0;  // dummy initialise\n                source.ip.family = TCP_ONION_FAMILY;\n                source.ip.ip6.uint32[0] = con_id;\n                source.ip.ip6.uint32[1] = 0;\n                source.ip.ip6.uint64[1] = con->identifier;\n                onion_send_1(TCP_server->onion, data + 1 + crypto_box_NONCEBYTES, length - (1 + crypto_box_NONCEBYTES), source,\n                             data + 1);\n            }\n\n            return 0;\n        }\n\n        case TCP_PACKET_ONION_RESPONSE: {\n            return -1;\n        }\n\n        default: {\n            if (data[0] < NUM_RESERVED_PORTS)\n                return -1;\n\n            uint8_t c_id = data[0] - NUM_RESERVED_PORTS;\n\n            if (c_id >= NUM_CLIENT_CONNECTIONS)\n                return -1;\n\n            if (con->connections[c_id].status == 0)\n                return -1;\n\n            if (con->connections[c_id].status != 2)\n                return 0;\n\n            uint32_t index = con->connections[c_id].index;\n            uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS;\n            uint8_t new_data[length];\n            memcpy(new_data, data, length);\n            new_data[0] = other_c_id;\n            int ret = write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[index], new_data, length, 0);\n\n            if (ret == -1)\n                return -1;\n\n            return 0;\n        }\n    }\n\n    return 0;\n}\n\n\nstatic int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection *con, const uint8_t *data,\n                                  uint16_t length)\n{\n    int index = add_accepted(TCP_server, con);\n\n    if (index == -1) {\n        kill_TCP_connection(con);\n        return -1;\n    }\n\n    sodium_memzero(con, sizeof(TCP_Secure_Connection));\n\n    if (handle_TCP_packet(TCP_server, index, data, length) == -1) {\n        kill_accepted(TCP_server, index);\n        return -1;\n    }\n\n    return index;\n}\n\n/* return index on success\n * return -1 on failure\n */\nstatic int accept_connection(TCP_Server *TCP_server, sock_t sock)\n{\n    if (!sock_valid(sock))\n        return -1;\n\n    if (!set_socket_nonblock(sock)) {\n        kill_sock(sock);\n        return -1;\n    }\n\n    if (!set_socket_nosigpipe(sock)) {\n        kill_sock(sock);\n        return -1;\n    }\n\n    uint16_t index = TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS;\n\n    TCP_Secure_Connection *conn = &TCP_server->incomming_connection_queue[index];\n\n    if (conn->status != TCP_STATUS_NO_STATUS)\n        kill_TCP_connection(conn);\n\n    conn->status = TCP_STATUS_CONNECTED;\n    conn->sock = sock;\n    conn->next_packet_length = 0;\n\n    ++TCP_server->incomming_connection_queue_index;\n    return index;\n}\n\nstatic sock_t new_listening_TCP_socket(int family, uint16_t port)\n{\n    sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP);\n\n    if (!sock_valid(sock)) {\n        return ~0;\n    }\n\n    int ok = set_socket_nonblock(sock);\n\n    if (ok && family == AF_INET6) {\n        ok = set_socket_dualstack(sock);\n    }\n\n    if (ok) {\n        ok = set_socket_reuseaddr(sock);\n    }\n\n    ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0);\n\n    if (!ok) {\n        kill_sock(sock);\n        return ~0;\n    }\n\n    return sock;\n}\n\nTCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key,\n                           Onion *onion)\n{\n    if (num_sockets == 0 || ports == NULL)\n        return NULL;\n\n    if (networking_at_startup() != 0) {\n        return NULL;\n    }\n\n    TCP_Server *temp = calloc(1, sizeof(TCP_Server));\n\n    if (temp == NULL)\n        return NULL;\n\n    temp->socks_listening = calloc(num_sockets, sizeof(sock_t));\n\n    if (temp->socks_listening == NULL) {\n        free(temp);\n        return NULL;\n    }\n\n#ifdef TCP_SERVER_USE_EPOLL\n    temp->efd = epoll_create(8);\n\n    if (temp->efd == -1) {\n        free(temp->socks_listening);\n        free(temp);\n        return NULL;\n    }\n\n#endif\n\n    uint8_t family;\n\n    if (ipv6_enabled) {\n        family = AF_INET6;\n    } else {\n        family = AF_INET;\n    }\n\n    uint32_t i;\n#ifdef TCP_SERVER_USE_EPOLL\n    struct epoll_event ev;\n#endif\n\n    for (i = 0; i < num_sockets; ++i) {\n        sock_t sock = new_listening_TCP_socket(family, ports[i]);\n\n        if (sock_valid(sock)) {\n#ifdef TCP_SERVER_USE_EPOLL\n            ev.events = EPOLLIN | EPOLLET;\n            ev.data.u64 = sock | ((uint64_t)TCP_SOCKET_LISTENING << 32);\n\n            if (epoll_ctl(temp->efd, EPOLL_CTL_ADD, sock, &ev) == -1) {\n                continue;\n            }\n\n#endif\n\n            temp->socks_listening[temp->num_listening_socks] = sock;\n            ++temp->num_listening_socks;\n        }\n    }\n\n    if (temp->num_listening_socks == 0) {\n        free(temp->socks_listening);\n        free(temp);\n        return NULL;\n    }\n\n    if (onion) {\n        temp->onion = onion;\n        set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp);\n    }\n\n    memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES);\n    crypto_scalarmult_curve25519_base(temp->public_key, temp->secret_key);\n\n    bs_list_init(&temp->accepted_key_list, crypto_box_PUBLICKEYBYTES, 8);\n\n    return temp;\n}\n\nstatic void do_TCP_accept_new(TCP_Server *TCP_server)\n{\n    uint32_t i;\n\n    for (i = 0; i < TCP_server->num_listening_socks; ++i) {\n        struct sockaddr_storage addr;\n        unsigned int addrlen = sizeof(addr);\n        sock_t sock;\n\n        do {\n            sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen);\n        } while (accept_connection(TCP_server, sock) != -1);\n    }\n}\n\nstatic int do_incoming(TCP_Server *TCP_server, uint32_t i)\n{\n    if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED)\n        return -1;\n\n    int ret = read_connection_handshake(&TCP_server->incomming_connection_queue[i], TCP_server->secret_key);\n\n    if (ret == -1) {\n        kill_TCP_connection(&TCP_server->incomming_connection_queue[i]);\n    } else if (ret == 1) {\n        int index_new = TCP_server->unconfirmed_connection_queue_index % MAX_INCOMMING_CONNECTIONS;\n        TCP_Secure_Connection *conn_old = &TCP_server->incomming_connection_queue[i];\n        TCP_Secure_Connection *conn_new = &TCP_server->unconfirmed_connection_queue[index_new];\n\n        if (conn_new->status != TCP_STATUS_NO_STATUS)\n            kill_TCP_connection(conn_new);\n\n        memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection));\n        sodium_memzero(conn_old, sizeof(TCP_Secure_Connection));\n        ++TCP_server->unconfirmed_connection_queue_index;\n\n        return index_new;\n    }\n\n    return -1;\n}\n\nstatic int do_unconfirmed(TCP_Server *TCP_server, uint32_t i)\n{\n    TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i];\n\n    if (conn->status != TCP_STATUS_UNCONFIRMED)\n        return -1;\n\n    uint8_t packet[MAX_PACKET_SIZE];\n    int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce,\n              packet, sizeof(packet));\n\n    if (len == 0) {\n        return -1;\n    } else if (len == -1) {\n        kill_TCP_connection(conn);\n        return -1;\n    } else {\n        return confirm_TCP_connection(TCP_server, conn, packet, len);\n    }\n}\n\nstatic void do_confirmed_recv(TCP_Server *TCP_server, uint32_t i)\n{\n    TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i];\n\n    uint8_t packet[MAX_PACKET_SIZE];\n    int len;\n\n    while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key,\n                  conn->recv_nonce, packet, sizeof(packet)))) {\n        if (len == -1) {\n            kill_accepted(TCP_server, i);\n            break;\n        }\n\n        if (handle_TCP_packet(TCP_server, i, packet, len) == -1) {\n            kill_accepted(TCP_server, i);\n            break;\n        }\n    }\n}\n\nstatic void do_TCP_incomming(TCP_Server *TCP_server)\n{\n    uint32_t i;\n\n    for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) {\n        do_incoming(TCP_server, i);\n    }\n}\n\nstatic void do_TCP_unconfirmed(TCP_Server *TCP_server)\n{\n    uint32_t i;\n\n    for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) {\n        do_unconfirmed(TCP_server, i);\n    }\n}\n\nstatic void do_TCP_confirmed(TCP_Server *TCP_server)\n{\n#ifdef TCP_SERVER_USE_EPOLL\n\n    if (TCP_server->last_run_pinged == unix_time())\n        return;\n\n    TCP_server->last_run_pinged = unix_time();\n#endif\n    uint32_t i;\n\n    for (i = 0; i < TCP_server->size_accepted_connections; ++i) {\n        TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i];\n\n        if (conn->status != TCP_STATUS_CONFIRMED)\n            continue;\n\n        if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) {\n            uint8_t ping[1 + sizeof(uint64_t)];\n            ping[0] = TCP_PACKET_PING;\n            uint64_t ping_id = random_64b();\n\n            if (!ping_id)\n                ++ping_id;\n\n            memcpy(ping + 1, &ping_id, sizeof(uint64_t));\n            int ret = write_packet_TCP_secure_connection(conn, ping, sizeof(ping), 1);\n\n            if (ret == 1) {\n                conn->last_pinged = unix_time();\n                conn->ping_id = ping_id;\n            } else {\n                if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) {\n                    kill_accepted(TCP_server, i);\n                    continue;\n                }\n            }\n        }\n\n        if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) {\n            kill_accepted(TCP_server, i);\n            continue;\n        }\n\n        send_pending_data(conn);\n\n#ifndef TCP_SERVER_USE_EPOLL\n\n        do_confirmed_recv(TCP_server, i);\n\n#endif\n    }\n}\n\n#ifdef TCP_SERVER_USE_EPOLL\nstatic void do_TCP_epoll(TCP_Server *TCP_server)\n{\n#define MAX_EVENTS 16\n    struct epoll_event events[MAX_EVENTS];\n    int nfds;\n\n    while ((nfds = epoll_wait(TCP_server->efd, events, MAX_EVENTS, 0)) > 0) {\n        int n;\n\n        for (n = 0; n < nfds; ++n) {\n            sock_t sock = events[n].data.u64 & 0xFFFFFFFF;\n            int status = (events[n].data.u64 >> 32) & 0xFF, index = (events[n].data.u64 >> 40);\n\n            if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || (events[n].events & EPOLLRDHUP)) {\n                switch (status) {\n                    case TCP_SOCKET_LISTENING: {\n                        //should never happen\n                        break;\n                    }\n\n                    case TCP_SOCKET_INCOMING: {\n                        kill_TCP_connection(&TCP_server->incomming_connection_queue[index]);\n                        break;\n                    }\n\n                    case TCP_SOCKET_UNCONFIRMED: {\n                        kill_TCP_connection(&TCP_server->unconfirmed_connection_queue[index]);\n                        break;\n                    }\n\n                    case TCP_SOCKET_CONFIRMED: {\n                        kill_accepted(TCP_server, index);\n                        break;\n                    }\n                }\n\n                continue;\n            }\n\n\n            if (!(events[n].events & EPOLLIN)) {\n                continue;\n            }\n\n            switch (status) {\n                case TCP_SOCKET_LISTENING: {\n                    //socket is from socks_listening, accept connection\n                    struct sockaddr_storage addr;\n                    unsigned int addrlen = sizeof(addr);\n\n                    while (1) {\n                        sock_t sock_new = accept(sock, (struct sockaddr *)&addr, &addrlen);\n\n                        if (!sock_valid(sock_new)) {\n                            break;\n                        }\n\n                        int index_new = accept_connection(TCP_server, sock_new);\n\n                        if (index_new == -1) {\n                            continue;\n                        }\n\n                        struct epoll_event ev = {\n                            .events = EPOLLIN | EPOLLET | EPOLLRDHUP,\n                            .data.u64 = sock_new | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 40)\n                        };\n\n                        if (epoll_ctl(TCP_server->efd, EPOLL_CTL_ADD, sock_new, &ev) == -1) {\n                            kill_TCP_connection(&TCP_server->incomming_connection_queue[index_new]);\n                            continue;\n                        }\n                    }\n\n                    break;\n                }\n\n                case TCP_SOCKET_INCOMING: {\n                    int index_new;\n\n                    if ((index_new = do_incoming(TCP_server, index)) != -1) {\n                        events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP;\n                        events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 40);\n\n                        if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) {\n                            kill_TCP_connection(&TCP_server->unconfirmed_connection_queue[index_new]);\n                            break;\n                        }\n                    }\n\n                    break;\n                }\n\n                case TCP_SOCKET_UNCONFIRMED: {\n                    int index_new;\n\n                    if ((index_new = do_unconfirmed(TCP_server, index)) != -1) {\n                        events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP;\n                        events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 40);\n\n                        if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) {\n                            //remove from confirmed connections\n                            kill_accepted(TCP_server, index_new);\n                            break;\n                        }\n                    }\n\n                    break;\n                }\n\n                case TCP_SOCKET_CONFIRMED: {\n                    do_confirmed_recv(TCP_server, index);\n                    break;\n                }\n            }\n        }\n    }\n\n#undef MAX_EVENTS\n}\n#endif\n\nvoid do_TCP_server(TCP_Server *TCP_server)\n{\n    unix_time_update();\n\n#ifdef TCP_SERVER_USE_EPOLL\n    do_TCP_epoll(TCP_server);\n\n#else\n    do_TCP_accept_new(TCP_server);\n    do_TCP_incomming(TCP_server);\n    do_TCP_unconfirmed(TCP_server);\n#endif\n\n    do_TCP_confirmed(TCP_server);\n}\n\nvoid kill_TCP_server(TCP_Server *TCP_server)\n{\n    uint32_t i;\n\n    for (i = 0; i < TCP_server->num_listening_socks; ++i) {\n        kill_sock(TCP_server->socks_listening[i]);\n    }\n\n    if (TCP_server->onion) {\n        set_callback_handle_recv_1(TCP_server->onion, NULL, NULL);\n    }\n\n    bs_list_free(&TCP_server->accepted_key_list);\n\n#ifdef TCP_SERVER_USE_EPOLL\n    close(TCP_server->efd);\n#endif\n\n    free(TCP_server->socks_listening);\n    free(TCP_server->accepted_connection_array);\n    free(TCP_server);\n}\n"
  },
  {
    "path": "toxcore/TCP_server.h",
    "content": "/*\n* TCP_server.h -- Implementation of the TCP relay server part of Tox.\n*\n*  Copyright (C) 2014 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n#ifndef TCP_SERVER_H\n#define TCP_SERVER_H\n\n#include \"crypto_core.h\"\n#include \"onion.h\"\n#include \"list.h\"\n\n#ifdef TCP_SERVER_USE_EPOLL\n#include \"sys/epoll.h\"\n#endif\n\n#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MACH__)\n#define MSG_NOSIGNAL 0\n#endif\n\n#define MAX_INCOMMING_CONNECTIONS 256\n\n#define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS\n\n#define MAX_PACKET_SIZE 2048\n\n#define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)\n#define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)\n#define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE)\n#define TCP_MAX_OOB_DATA_LENGTH 1024\n\n#define NUM_RESERVED_PORTS 16\n#define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS)\n\n#define TCP_PACKET_ROUTING_REQUEST  0\n#define TCP_PACKET_ROUTING_RESPONSE 1\n#define TCP_PACKET_CONNECTION_NOTIFICATION 2\n#define TCP_PACKET_DISCONNECT_NOTIFICATION 3\n#define TCP_PACKET_PING 4\n#define TCP_PACKET_PONG 5\n#define TCP_PACKET_OOB_SEND 6\n#define TCP_PACKET_OOB_RECV 7\n#define TCP_PACKET_ONION_REQUEST  8\n#define TCP_PACKET_ONION_RESPONSE 9\n\n#define ARRAY_ENTRY_SIZE 6\n\n/* frequency to ping connected nodes and timeout in seconds */\n#define TCP_PING_FREQUENCY 30\n#define TCP_PING_TIMEOUT 10\n\n#ifdef TCP_SERVER_USE_EPOLL\n#define TCP_SOCKET_LISTENING 0\n#define TCP_SOCKET_INCOMING 1\n#define TCP_SOCKET_UNCONFIRMED 2\n#define TCP_SOCKET_CONFIRMED 3\n#endif\n\nenum {\n    TCP_STATUS_NO_STATUS,\n    TCP_STATUS_CONNECTED,\n    TCP_STATUS_UNCONFIRMED,\n    TCP_STATUS_CONFIRMED,\n};\n\ntypedef struct TCP_Priority_List TCP_Priority_List;\n\nstruct TCP_Priority_List {\n    TCP_Priority_List *next;\n    uint16_t size, sent;\n    uint8_t data[];\n};\n\ntypedef struct TCP_Secure_Connection {\n    uint8_t status;\n    sock_t  sock;\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */\n    uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    uint16_t next_packet_length;\n    struct {\n        uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */\n        uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n        uint32_t index;\n        uint8_t other_id;\n    } connections[NUM_CLIENT_CONNECTIONS];\n    uint8_t last_packet[2 + MAX_PACKET_SIZE];\n    uint16_t last_packet_length;\n    uint16_t last_packet_sent;\n\n    TCP_Priority_List *priority_queue_start, *priority_queue_end;\n\n    uint64_t identifier;\n\n    uint64_t last_pinged;\n    uint64_t ping_id;\n} TCP_Secure_Connection;\n\n\ntypedef struct {\n    Onion *onion;\n\n#ifdef TCP_SERVER_USE_EPOLL\n    int efd;\n    uint64_t last_run_pinged;\n#endif\n    sock_t *socks_listening;\n    unsigned int num_listening_socks;\n\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t secret_key[crypto_box_SECRETKEYBYTES];\n    TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS];\n    uint16_t incomming_connection_queue_index;\n    TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMMING_CONNECTIONS];\n    uint16_t unconfirmed_connection_queue_index;\n\n    TCP_Secure_Connection *accepted_connection_array;\n    uint32_t size_accepted_connections;\n    uint32_t num_accepted_connections;\n\n    uint64_t counter;\n\n    BS_LIST accepted_key_list;\n} TCP_Server;\n\n/* Create new TCP server instance.\n */\nTCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key,\n                           Onion *onion);\n\nvoid wipe_priority_list(TCP_Priority_List *p);\n\n/* Run the TCP_server\n */\nvoid do_TCP_server(TCP_Server *TCP_server);\n\n/* Kill the TCP server\n */\nvoid kill_TCP_server(TCP_Server *TCP_server);\n\n/* return the amount of data in the tcp recv buffer.\n * return 0 on failure.\n */\nunsigned int TCP_socket_data_recv_buffer(sock_t sock);\n\n/* Read the next two bytes in TCP stream then convert them to\n * length (host byte order).\n *\n * return length on success\n * return 0 if nothing has been read from socket.\n * return ~0 on failure.\n */\nuint16_t read_TCP_length(sock_t sock);\n\n/* Read length bytes from socket.\n *\n * return length on success\n * return -1 on failure/no data in buffer.\n */\nint read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length);\n\n/* return length of received packet on success.\n * return 0 if could not read any packet.\n * return -1 on failure (connection must be killed).\n */\nint read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, const uint8_t *shared_key,\n                                      uint8_t *recv_nonce, uint8_t *data, uint16_t max_len);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/assoc.c",
    "content": "\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"logger.h\"\n#include \"DHT.h\"\n#include \"assoc.h\"\n#include \"ping.h\"\n\n#include \"LAN_discovery.h\"\n\n#include <assert.h>\n#include \"util.h\"\n\n/*\n *        BASIC OVERVIEW:\n *\n * Hash: The client_id is hashed with a local hash function.\n * Hashes are used in multiple places for searching.\n * Bucket: The first n bits of the client_id are used to\n * select a bucket. This speeds up sorting, but the more\n * important reason is to enforce a spread in the space of\n * client_ids available.\n *\n *\n * Candidates:\n *\n * Candidates are kept in buckets of hash tables. The hash\n * function is calculated from the client_id. Up to\n * HASH_COLLIDE_COUNT alternative positions are tried if\n * the initial position is already used by a different entry.\n * The collision function is multiplicative, not additive.\n *\n * A new candidate can bump an existing candidate, if it is\n * more \"desirable\": Seen beats Heard.\n */\n\n/* candidates: alternative places for the same hash value */\n#define HASH_COLLIDE_COUNT 5\n\n/* bucket size shall be co-prime to this */\n#define HASH_COLLIDE_PRIME 101\n\n/* candidates: bump entries: timeout values for seen/heard to be considered of value */\n#define CANDIDATES_SEEN_TIMEOUT 1800\n#define CANDIDATES_HEARD_TIMEOUT 600\n\n/* distance/index: index size & access mask */\n#define DISTANCE_INDEX_INDEX_BITS (64 - DISTANCE_INDEX_DISTANCE_BITS)\n#define DISTANCE_INDEX_INDEX_MASK ((1 << DISTANCE_INDEX_INDEX_BITS) - 1)\n\n/* types to stay consistent */\ntypedef uint16_t bucket_t;\ntypedef uint32_t hash_t;\ntypedef uint16_t usecnt_t;\n\n/* abbreviations ... */\ntypedef Assoc_distance_relative_callback dist_rel_cb;\ntypedef Assoc_distance_absolute_callback dist_abs_cb;\n\n/*\n * Client_data wrapped with additional data\n */\ntypedef struct Client_entry {\n    hash_t             hash;\n\n    /* shortcuts & rumors: timers and data */\n    uint64_t           getnodes;\n    uint64_t           used_at;\n\n    uint64_t           seen_at;\n    uint64_t           heard_at;\n\n    uint16_t           seen_family;\n    uint16_t           heard_family;\n\n    IP_Port            assoc_heard4;\n    IP_Port            assoc_heard6;\n\n    Client_data        client;\n} Client_entry;\n\ntypedef struct candidates_bucket {\n    Client_entry          *list;                               /* hashed list */\n} candidates_bucket;\n\nstruct Assoc {\n    hash_t                 self_hash;                          /* hash of self_client_id */\n    uint8_t                self_client_id[crypto_box_PUBLICKEYBYTES];     /* don't store entries for this */\n\n    /* association centralization: clients not in use */\n    size_t                 candidates_bucket_bits;\n    size_t                 candidates_bucket_count;\n    size_t                 candidates_bucket_size;\n    candidates_bucket     *candidates;\n    uint64_t               getnodes;\n};\n\n/*****************************************************************************/\n/*                             HELPER FUNCTIONS                              */\n/*****************************************************************************/\n\n/* the complete distance would be crypto_box_PUBLICKEYBYTES long...\n * returns DISTANCE_INDEX_DISTANCE_BITS valid bits */\nstatic uint64_t id_distance(const Assoc *assoc, void *callback_data, const uint8_t *id_ref, const uint8_t *id_test)\n{\n    /* with BIG_ENDIAN, this would be a one-liner... */\n    uint64_t retval = 0;\n\n    uint8_t pos = 0, bits = DISTANCE_INDEX_DISTANCE_BITS;\n\n    while (bits > 8) {\n        uint8_t distance = abs((int8_t)id_ref[pos] ^ (int8_t)id_test[pos]);\n        retval = (retval << 8) | distance;\n        bits -= 8;\n        pos++;\n    }\n\n    return (retval << bits) | ((id_ref[pos] ^ id_test[pos]) >> (8 - bits));\n}\n\n/* qsort() callback for a sorting by id_distance() values */\nstatic int dist_index_comp(const void *a, const void *b)\n{\n    const uint64_t *_a = a;\n    const uint64_t *_b = b;\n\n    if (*_a < *_b)\n        return -1;\n\n    if (*_a > *_b)\n        return 1;\n\n    return 0;\n}\n\n/* get actual entry to a distance_index */\nstatic Client_entry *dist_index_entry(Assoc *assoc, uint64_t dist_ind)\n{\n    if ((dist_ind & DISTANCE_INDEX_INDEX_MASK) == DISTANCE_INDEX_INDEX_MASK)\n        return NULL;\n\n    size_t total = assoc->candidates_bucket_count * assoc->candidates_bucket_size;\n    uint32_t index = dist_ind & DISTANCE_INDEX_INDEX_MASK;\n\n    if (index < total) {\n        bucket_t b_id = index / assoc->candidates_bucket_size;\n        candidates_bucket *cnd_bckt = &assoc->candidates[b_id];\n        size_t b_ix = index % assoc->candidates_bucket_size;\n        Client_entry *entry = &cnd_bckt->list[b_ix];\n\n        if (entry->hash)\n            return entry;\n    }\n\n    return NULL;\n}\n\n/* get actual entry's public_key to a distance_index */\nstatic uint8_t *dist_index_id(Assoc *assoc, uint64_t dist_ind)\n{\n    Client_entry *entry = dist_index_entry(assoc, dist_ind);\n\n    if (entry)\n        return entry->client.public_key;\n\n    return NULL;\n}\n\n/* sorts first .. last, i.e. last is included */\nstatic void dist_index_bubble(Assoc *assoc, uint64_t *dist_list, size_t first, size_t last, uint8_t *id,\n                              void *custom_data, Assoc_distance_relative_callback dist_rel_func)\n{\n    size_t i, k;\n\n    for (i = first; i <= last; i++) {\n        uint8_t *id1 = dist_index_id(assoc, dist_list[i]);\n\n        for (k = i + 1; k <= last; k++) {\n            uint8_t *id2 = dist_index_id(assoc, dist_list[k]);\n\n            if (id1 && id2)\n                if (dist_rel_func(assoc, custom_data, id, id1, id2) == 2) {\n                    uint64_t swap = dist_list[i];\n                    dist_list[i] = dist_list[k];\n                    dist_list[k] = swap;\n                }\n        }\n    }\n}\n\n/* TODO: Check that there isn't a function like this elsewhere hidden.\n * E.g. the one which creates a handshake_id isn't usable for this, it must\n * always map the same ID to the same hash.\n *\n * Result is NOT MAPPED to CANDIDATES_TO_KEEP range, i.e. map before using\n * it for list access. */\nstatic hash_t id_hash(const Assoc *assoc, const uint8_t *id)\n{\n    uint32_t i, res = 0x19a64e82;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++)\n        res = ((res << 1) ^ id[i]) + (res >> 31);\n\n    /* can't have zero as hash, a) marks an unused spot,\n     * b) collision function is multiplicative */\n    if (!(res % assoc->candidates_bucket_size))\n        res++;\n\n    return res;\n}\n\n/* up to HASH_COLLIDE_COUNT calls to different spots,\n * result IS mapped to CANDIDATES_TO_KEEP range */\nstatic hash_t hash_collide(const Assoc *assoc, hash_t hash)\n{\n    uint64_t hash64 = hash % assoc->candidates_bucket_size;\n    hash64 = (hash64 * HASH_COLLIDE_PRIME) % assoc->candidates_bucket_size;\n\n    hash_t retval = hash64;\n\n    /* this should never happen when CANDIDATES_TO_KEEP is prime and hash not a multiple\n     * (id_hash() checks for a multiple and returns a different hash in that case)\n     *\n     * ( 1 .. (prime - 1) is a group over multiplication and every number has its inverse\n     *   in the group, so no multiplication should ever end on zero as long neither\n     *   of the two factors was zero-equivalent )\n     *\n     * BUT: because the usage of the word \"never\" invokes Murphy's law, catch it */\n    if (!retval) {\n#ifdef DEBUG\n        fprintf(stderr, \"assoc::hash_collide: hash %u, bucket size %u => %u!\", hash, (uint)assoc->candidates_bucket_size,\n                retval);\n        assert(retval != 0);\n#endif\n        retval = 1;\n    }\n\n    return retval;\n}\n\n/* returns the \"seen\" assoc related to the ipp */\nstatic IPPTsPng *entry_assoc(Client_entry *cl_entry, const IP_Port *ipp)\n{\n    if (!cl_entry)\n        return NULL;\n\n    if (ipp->ip.family == AF_INET)\n        return &cl_entry->client.assoc4;\n\n    if (ipp->ip.family == AF_INET6)\n        return &cl_entry->client.assoc6;\n\n    return NULL;\n}\n\n/* returns the \"heard\" assoc related to the ipp */\nstatic IP_Port *entry_heard_get(Client_entry *entry, const IP_Port *ipp)\n{\n    if (ipp->ip.family == AF_INET)\n        return &entry->assoc_heard4;\n    else if (ipp->ip.family == AF_INET6)\n        return &entry->assoc_heard6;\n    else\n        return NULL;\n}\n\n/* store a \"heard\" entry\n * overwrites empty entry, does NOT overwrite non-LAN ip with\n * LAN ip\n *\n * returns 1 if the entry did change */\nstatic int entry_heard_store(Client_entry *entry, const IPPTs *ippts)\n{\n    if (!entry || !ippts)\n        return 0;\n\n    if (!ipport_isset(&ippts->ip_port))\n        return 0;\n\n    IP_Port  *heard;\n    const IP_Port  *ipp = &ippts->ip_port;\n\n    if (ipp->ip.family == AF_INET)\n        heard = &entry->assoc_heard4;\n    else if (ipp->ip.family == AF_INET6)\n        heard = &entry->assoc_heard6;\n    else\n        return 0;\n\n    if (ipport_equal(ipp, heard))\n        return 0;\n\n    if (!ipport_isset(heard)) {\n        *heard = *ipp;\n        entry->heard_at = ippts->timestamp;\n        entry->heard_family = ipp->ip.family;\n        return 1;\n    }\n\n    /* don't destroy a good address with a crappy one\n     * (unless we're very timed out) */\n    uint8_t LAN_ipp = LAN_ip(ipp->ip) == 0;\n    uint8_t LAN_entry = LAN_ip(heard->ip) == 0;\n\n    if (LAN_ipp && !LAN_entry && !is_timeout(entry->heard_at, CANDIDATES_HEARD_TIMEOUT))\n        return 0;\n\n    *heard = *ipp;\n    entry->heard_at = ippts->timestamp;\n    entry->heard_family = ipp->ip.family;\n\n    return 1;\n}\n\n/* maps Assoc callback signature to id_closest() */\nstatic int assoc_id_closest(const Assoc *assoc, void *callback_data, const uint8_t *client_id,\n                            const uint8_t *client_id1, const uint8_t *client_id2)\n{\n    return id_closest(client_id, client_id1, client_id2);\n}\n\nstatic bucket_t id_bucket(const uint8_t *id, uint8_t bits)\n{\n    /* return the first \"bits\" bits of id */\n    bucket_t retval = 0;\n\n    uint8_t pos = 0;\n\n    while (bits > 8) {\n        retval = (retval << 8) | id[pos++];\n        bits -= 8;\n    }\n\n    return (retval << bits) | (id[pos] >> (8 - bits));\n}\n\n/*****************************************************************************/\n/*                          CANDIDATES FUNCTIONS                             */\n/*****************************************************************************/\n\n\nstatic bucket_t candidates_id_bucket(const Assoc *assoc, const uint8_t *id)\n{\n    return id_bucket(id, assoc->candidates_bucket_bits);\n}\n\nstatic uint8_t candidates_search(const Assoc *assoc, const uint8_t *id, hash_t hash, Client_entry **entryptr)\n{\n    bucket_t bucket = candidates_id_bucket(assoc, id);\n    candidates_bucket *cnd_bckt = &assoc->candidates[bucket];\n    size_t coll, pos = hash % assoc->candidates_bucket_size;\n\n    for (coll = 0; coll < HASH_COLLIDE_COUNT; pos = hash_collide(assoc, pos) , coll++) {\n        Client_entry *entry = &cnd_bckt->list[pos];\n\n        if (entry->hash == hash)\n            if (id_equal(entry->client.public_key, id)) {\n                *entryptr = entry;\n                return 1;\n            }\n    }\n\n    *entryptr = NULL;\n    return 0;\n}\n\nstatic void candidates_update_assoc(const Assoc *assoc, Client_entry *entry, uint8_t used, const IPPTs *ippts_send,\n                                    const IP_Port *ipp_recv)\n{\n    if (!assoc || !entry || !ippts_send)\n        return;\n\n    IPPTsPng *ipptsp = entry_assoc(entry, &ippts_send->ip_port);\n\n    if (!ipptsp)\n        return;\n\n    if (used)\n        entry->used_at = unix_time();\n\n    /* do NOT do anything related to wanted, that's handled outside,\n     * just update the assoc (in the most sensible way)\n     */\n    if (ipp_recv) {\n        ipptsp->ip_port = ippts_send->ip_port;\n        ipptsp->timestamp = ippts_send->timestamp;\n        ipptsp->ret_ip_port = *ipp_recv;\n        ipptsp->ret_timestamp = unix_time();\n\n        entry->seen_at = unix_time();\n        entry->seen_family = ippts_send->ip_port.ip.family;\n\n        return;\n    }\n\n    entry_heard_store(entry, ippts_send);\n}\n\nstatic uint8_t candidates_create_internal(const Assoc *assoc, hash_t const hash, const uint8_t *id, uint8_t seen,\n        uint8_t used, bucket_t *bucketptr, size_t *posptr)\n{\n    if (!assoc || !id || !bucketptr ||  !posptr)\n        return 0;\n\n    bucket_t bucket = candidates_id_bucket(assoc, id);\n    candidates_bucket *cnd_bckt = &assoc->candidates[bucket];\n\n    size_t coll, pos = hash % assoc->candidates_bucket_size, check;\n    size_t pos_check[6];\n\n    memset(pos_check, 0, sizeof(pos_check));\n\n    for (coll = 0; coll < HASH_COLLIDE_COUNT; pos = hash_collide(assoc, pos) , coll++) {\n        Client_entry *entry = &cnd_bckt->list[pos];\n\n        /* unset */\n        if (!entry->hash) {\n            *bucketptr = bucket;\n            *posptr = pos;\n\n            return 1;\n        }\n\n        /* 0. bad\n         * 1. seen bad, heard good\n         * 2. seen good\n         * 3. used */\n        // enumerated lists are superior to magic numbers\n        if (!is_timeout(entry->used_at, BAD_NODE_TIMEOUT))\n            check = USED;\n        else if (!is_timeout(entry->seen_at, CANDIDATES_SEEN_TIMEOUT))\n            check = SEENG;\n        else if (!is_timeout(entry->heard_at, CANDIDATES_HEARD_TIMEOUT))\n            check = SEENB_HEARDG;\n        else\n            check = BAD;\n\n        if (!pos_check[check])\n            pos_check[check] = pos + 1;\n    }\n\n    /* used > seen > heard > bad */\n    size_t i, pos_max = used ? USED : (seen ? SEENG : SEENB_HEARDG);\n\n    for (i = 0; i < pos_max; i++)\n        if (pos_check[i]) {\n            *bucketptr = bucket;\n            *posptr = pos_check[i] - 1;\n\n            return 1;\n        }\n\n    return 0;\n}\n\nstatic uint8_t candidates_create_new(const Assoc *assoc, hash_t hash, const uint8_t *id, uint8_t used,\n                                     const IPPTs *ippts_send, const IP_Port *ipp_recv)\n{\n    if (!assoc || !id || !ippts_send)\n        return 0;\n\n    bucket_t bucket;\n    size_t pos;\n\n    if (!candidates_create_internal(assoc, hash, id, ipp_recv != NULL, used, &bucket, &pos))\n        return 0;\n\n    candidates_bucket *cnd_bckt = &assoc->candidates[bucket];\n    Client_entry *entry = &cnd_bckt->list[pos];\n    memset(entry, 0, sizeof(*entry));\n    IPPTsPng *ipptsp = entry_assoc(entry, &ippts_send->ip_port);\n\n    if (!ipptsp)\n        return 0;\n\n    entry->hash = hash;\n    id_copy(entry->client.public_key, id);\n\n    if (used)\n        entry->used_at = unix_time();\n\n    if (ipp_recv && !ipport_isset(ipp_recv))\n        ipp_recv = NULL;\n\n    if (ipp_recv) {\n        entry->seen_at = ippts_send->timestamp;\n        entry->seen_family = ippts_send->ip_port.ip.family;\n\n        ipptsp->ip_port = ippts_send->ip_port;\n        ipptsp->timestamp = ippts_send->timestamp;\n        ipptsp->ret_ip_port = *ipp_recv;\n        ipptsp->ret_timestamp = unix_time();\n    } else {\n        IP_Port *heard = entry_heard_get(entry, &ippts_send->ip_port);\n\n        if (heard) {\n            entry->heard_at = ippts_send->timestamp;\n            entry->heard_family = ippts_send->ip_port.ip.family;\n\n            *heard = ippts_send->ip_port;\n        }\n    }\n\n    return 1;\n}\n\n/*****************************************************************************/\n\nstatic void client_id_self_update(Assoc *assoc)\n{\n    if (assoc->self_hash)\n        return;\n\n    size_t i, sum = 0;\n\n    for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++)\n        sum |= assoc->self_client_id[i];\n\n    if (!sum)\n        return;\n\n    assoc->self_hash = id_hash(assoc, assoc->self_client_id);\n\n    LOGGER_DEBUG(\"id is now set, purging cache of self-references\");\n\n    /* if we already added some (or loaded some) entries,\n     * look and remove if we find a match\n     */\n    bucket_t b_id = candidates_id_bucket(assoc, assoc->self_client_id);\n    candidates_bucket *cnd_bckt = &assoc->candidates[b_id];\n    size_t pos = assoc->self_hash % assoc->candidates_bucket_size;\n\n    for (i = 0; i < HASH_COLLIDE_COUNT; pos = hash_collide(assoc, pos), i++) {\n        Client_entry *entry = &cnd_bckt->list[pos];\n\n        if (entry->hash == assoc->self_hash)\n            if (id_equal(entry->client.public_key, assoc->self_client_id))\n                entry->hash = 0;\n    }\n}\n\n/*****************************************************************************/\n/*                            TRIGGER FUNCTIONS                              */\n/*****************************************************************************/\n\n/* Central entry point for new associations: add a new candidate to the cache\n * seen should be 0 (zero), if the candidate was announced by someone else,\n * seen should be 1 (one), if there is confirmed connectivity (a definite response)\n */\nuint8_t Assoc_add_entry(Assoc *assoc, const uint8_t *id, const IPPTs *ippts_send, const IP_Port *ipp_recv, uint8_t used)\n{\n    if (!assoc || !id || !ippts_send)\n        return 0;\n\n    if (!assoc->self_hash) {\n        client_id_self_update(assoc);\n\n        if (!assoc->self_hash)\n            return 0;\n    }\n\n    if (!ipport_isset(&ippts_send->ip_port))\n        return 0;\n\n    if (ipp_recv && !ipport_isset(ipp_recv))\n        ipp_recv = NULL;\n\n    hash_t hash = id_hash(assoc, id);\n\n    if (hash == assoc->self_hash)\n        if (id_equal(id, assoc->self_client_id))\n            return 0;\n\n    /* if it's new:\n     * callback, if there's desire, add to clients, else to candidates\n     *\n     * if it's \"old\":\n     *    if it's client: refresh\n     *    if it's candidate:\n     *       if !ipp_recv, refresh\n     *       if ipp_recv: callback, if there's desire, move to candidates\n     */\n    Client_entry *cnd_entry;\n\n    if (!candidates_search(assoc, id, hash, &cnd_entry)) {\n        if (candidates_create_new(assoc, hash, id, used, ippts_send, ipp_recv))\n            return 1;\n        else\n            return 0;\n    } else {\n        candidates_update_assoc(assoc, cnd_entry, used, ippts_send, ipp_recv);\n        return 2;\n    }\n}\n\n/*****************************************************************************/\n/*                               MAIN USE                                    */\n/*****************************************************************************/\n\nuint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *state)\n{\n    if (!assoc || !state || !state->wanted_id || !state->result)\n        return 0;\n\n    if (!assoc->self_hash) {\n        client_id_self_update(assoc);\n\n        if (!assoc->self_hash)\n            return 0;\n    }\n\n    if (!state->distance_relative_func)\n        state->distance_relative_func = assoc_id_closest;\n\n    if (!state->distance_absolute_func)\n        state->distance_absolute_func = id_distance;\n\n    size_t dist_list_len = assoc->candidates_bucket_count * assoc->candidates_bucket_size;\n    uint64_t dist_list[dist_list_len];\n    memset(dist_list, ~0, dist_list_len * sizeof(dist_list[0]));\n    bucket_t b;\n    size_t i;\n\n    for (b = 0; b < assoc->candidates_bucket_count; b++) {\n        candidates_bucket *cnd_bckt = &assoc->candidates[b];\n\n        for (i = 0; i < assoc->candidates_bucket_size; i++) {\n            Client_entry *entry = &cnd_bckt->list[i];\n\n            if (entry->hash) {\n                if (state->flags & ProtoIPv4) {\n                    if (!ipport_isset(&entry->client.assoc4.ip_port))\n                        continue;\n\n                    if (!(state->flags & LANOk))\n                        if (!LAN_ip(entry->client.assoc4.ip_port.ip))\n                            continue;\n                }\n\n                if (state->flags & ProtoIPv6) {\n                    if (!ipport_isset(&entry->client.assoc6.ip_port))\n                        continue;\n\n                    if (!(state->flags & LANOk))\n                        if (!LAN_ip(entry->client.assoc6.ip_port.ip))\n                            continue;\n                }\n\n                uint64_t dist = state->distance_absolute_func(assoc, state->custom_data, state->wanted_id, entry->client.public_key);\n                uint32_t index = b * assoc->candidates_bucket_size + i;\n                dist_list[index] = (dist << DISTANCE_INDEX_INDEX_BITS) | index;\n            }\n        }\n    }\n\n    qsort(dist_list, dist_list_len, sizeof(dist_list[0]), dist_index_comp);\n\n    /* ok, ok, it's not *perfectly* sorted, because we used an absolute distance\n     * go over the result and see if we need to \"smoothen things out\"\n     * because those should be only very few and short streaks, the worst regularly\n     * used sorting function aka bubble sort is used */\n    uint64_t dist_prev = ~0;\n    size_t ind_prev = ~0, ind_curr;\n    size_t len = 1;\n\n    for (ind_curr = 0; ind_curr < dist_list_len; ind_curr++) {\n        /* sorted increasingly, so an invalid entry marks the end */\n        if ((dist_list[ind_curr] & DISTANCE_INDEX_INDEX_MASK) == DISTANCE_INDEX_INDEX_MASK)\n            break;\n\n        uint64_t dist_curr = dist_list[ind_curr] >> DISTANCE_INDEX_INDEX_BITS;\n\n        if (dist_prev == dist_curr)\n            len++;\n        else {\n            if (len > 1)\n                dist_index_bubble(assoc, dist_list, ind_prev, ind_curr - 1, state->wanted_id, state->custom_data,\n                                  state->distance_relative_func);\n\n            dist_prev = dist_curr;\n            ind_prev = ind_curr;\n            len = 1;\n        }\n    }\n\n    if (len > 1)\n        dist_index_bubble(assoc, dist_list, ind_prev, ind_curr - 1, state->wanted_id, state->custom_data,\n                          state->distance_relative_func);\n\n    /* ok, now dist_list is a strictly ascending sorted list of nodes\n     * a) extract CLOSE_QUOTA_USED clients, not timed out\n     * b) extract (1 - QUOTA) (better!) clients & candidates, not timed out\n     * c) save candidates which would be better, if contact can be established */\n    size_t client_quota_good = 0, pos = 0;\n    size_t client_quota_max = state->count_good;\n\n    ssize_t taken_last = - 1;\n\n    for (i = 0; (i < dist_list_len) && (pos < state->count); i++) {\n        /* sorted increasingly, so an invalid entry marks the end */\n        if ((dist_list[i] & DISTANCE_INDEX_INDEX_MASK) == DISTANCE_INDEX_INDEX_MASK)\n            break;\n\n        Client_entry *entry = dist_index_entry(assoc, dist_list[i]);\n\n        if (entry && entry->hash) {\n            if (client_quota_good >= client_quota_max) {\n                state->result[pos++] = &entry->client;\n                taken_last = i;\n            } else {\n                if (state->flags & (ProtoIPv4 | ProtoIPv6)) {\n                    if ((state->flags & ProtoIPv4) && is_timeout(entry->client.assoc4.timestamp, BAD_NODE_TIMEOUT))\n                        continue;\n\n                    if ((state->flags & ProtoIPv6) && is_timeout(entry->client.assoc6.timestamp, BAD_NODE_TIMEOUT))\n                        continue;\n                } else if (is_timeout(entry->seen_at, BAD_NODE_TIMEOUT))\n                    continue;\n\n                state->result[pos++] = &entry->client;\n                client_quota_good++;\n                taken_last = i;\n            }\n        }\n    }\n\n    /* if we had not enough valid entries the list might still not be filled.\n     *\n     * start again from last taken client, but leave out any requirement\n     */\n    if (pos < state->count) {\n        for (i = taken_last + 1; (i < dist_list_len) && (pos < state->count); i++) {\n            /* sorted increasingly, so an invalid entry marks the end */\n            if ((dist_list[i] & DISTANCE_INDEX_INDEX_MASK) == DISTANCE_INDEX_INDEX_MASK)\n                break;\n\n            Client_entry *entry = dist_index_entry(assoc, dist_list[i]);\n\n            if (entry && entry->hash)\n                state->result[pos++] = &entry->client;\n        }\n    }\n\n    return pos;\n}\n\n/*****************************************************************************/\n/*                     GLOBAL STRUCTURE FUNCTIONS                            */\n/*****************************************************************************/\n\nstatic uint8_t odd_min9_is_prime(size_t value)\n{\n    size_t i = 3;\n\n    while (i * i <= value) {\n        if (!(value % i))\n            return 0;\n\n        i += 2;\n    }\n\n    return 1;\n}\n\nstatic size_t prime_upto_min9(size_t limit)\n{\n    /* even => odd */\n    limit = limit - (1 - (limit % 2));\n\n    while (!odd_min9_is_prime(limit))\n        limit -= 2;\n\n    return limit;\n}\n\n/* create */\nAssoc *new_Assoc(size_t bits, size_t entries, const uint8_t *public_id)\n{\n    if (!public_id)\n        return NULL;\n\n    Assoc *assoc = calloc(1, sizeof(*assoc));\n\n    if (!assoc)\n        return NULL;\n\n    /*\n     * bits must be in [ 2 .. 15 ]\n     * entries must be a prime\n     */\n    if (bits < 2)\n        bits = 2;\n    else if (bits > 15)\n        bits = 15;\n\n    assoc->candidates_bucket_bits = bits;\n    assoc->candidates_bucket_count = 1U << bits;\n\n    if (entries < 25) {\n        if (entries <= 6)\n            entries = 5;\n        else {\n            entries = entries - (1 - (entries % 2)); /* even => odd */\n\n            /* 7..23: all odds but 9&15 are prime */\n            if (!(entries % 3)) /* 9, 15 */\n                entries -= 2;   /* 7, 13 */\n        }\n    } else if (entries > ((1 << 17) - 1)) /* 130k+ */\n        entries = (1 << 17) - 1;\n    else {\n        /* 9+: test and find a prime less or equal */\n        size_t entries_test = prime_upto_min9(entries);\n\n        if (entries_test == HASH_COLLIDE_PRIME) /* disallowed */\n            entries_test = prime_upto_min9(entries_test - 1);\n\n        if (entries_test != entries) {\n\n            LOGGER_DEBUG(\"trimmed %i to %i.\\n\", (int)entries, (int)entries_test);\n            entries = (size_t)entries_test;\n        }\n    }\n\n    assoc->candidates_bucket_size = entries;\n\n    /* allocation: preferably few blobs */\n    size_t bckt, cix;\n    Client_entry *clients = malloc(sizeof(*clients) * assoc->candidates_bucket_count * assoc->candidates_bucket_size);\n\n    if (!clients) {\n        free(assoc);\n        return NULL;\n    }\n\n    candidates_bucket *lists = malloc(sizeof(*lists) * assoc->candidates_bucket_count);\n\n    if (!lists) {\n        free(assoc);\n        free(clients);\n        return NULL;\n    }\n\n    for (bckt = 0; bckt < assoc->candidates_bucket_count; bckt++) {\n        candidates_bucket *list = &lists[bckt];\n\n        list->list = &clients[bckt * assoc->candidates_bucket_size];\n\n        for (cix = 0; cix < assoc->candidates_bucket_size; cix++)\n            list->list[cix].hash = 0;\n    }\n\n    assoc->candidates = lists;\n    assoc->getnodes = unix_time();\n\n    id_copy(assoc->self_client_id, public_id);\n    client_id_self_update(assoc);\n\n    return assoc;\n}\n\nAssoc *new_Assoc_default(const uint8_t *public_id)\n{\n    /* original 8, 251 averages to ~32k entries... probably the whole DHT :D\n     * 320 entries is fine, hopefully */\n    return new_Assoc(6, 15, public_id);\n}\n\n/* own client_id, assocs for this have to be ignored */\nvoid Assoc_self_client_id_changed(Assoc *assoc, const uint8_t *id)\n{\n    if (assoc && id) {\n        assoc->self_hash = 0;\n        id_copy(assoc->self_client_id, id);\n        client_id_self_update(assoc);\n    }\n}\n\n#ifdef TOX_LOGGER\nstatic char *idpart2str(uint8_t *id, size_t len);\n#endif /* TOX_LOGGER */\n\n/* refresh buckets */\nvoid do_Assoc(Assoc *assoc, DHT *dht)\n{\n    if (is_timeout(assoc->getnodes, ASSOC_BUCKET_REFRESH)) {\n        assoc->getnodes = unix_time();\n\n        size_t candidate = (rand() % assoc->candidates_bucket_count) + assoc->candidates_bucket_count;\n\n        /* in that bucket or the buckets closest to it:\n         * find the best heard candidate\n         * find the best seen candidate\n         * send getnode() requests to both */\n        uint8_t *target_id = NULL;\n        Client_entry *heard = NULL, *seen = NULL;\n        size_t i, k, m;\n\n        for (i = 1; i < assoc->candidates_bucket_count; i++) {\n            if (i % 2)\n                k = - (i >> 1);\n            else\n                k = i >> 1;\n\n            size_t bckt = (candidate + k) % assoc->candidates_bucket_count;\n\n            for (m = 0; m < assoc->candidates_bucket_size; m++)\n                if (assoc->candidates[bckt].list[m].hash) {\n                    Client_entry *entry = &assoc->candidates[bckt].list[m];\n\n                    if (!is_timeout(entry->getnodes, CANDIDATES_SEEN_TIMEOUT))\n                        continue;\n\n                    if (!target_id)\n                        target_id = entry->client.public_key;\n\n                    if (entry->seen_at) {\n                        if (!seen)\n                            if (!is_timeout(entry->seen_at, CANDIDATES_SEEN_TIMEOUT))\n                                seen = entry;\n                    }\n\n                    if (entry->heard_at) {\n                        if (!heard)\n                            if (!is_timeout(entry->heard_at, CANDIDATES_HEARD_TIMEOUT))\n                                heard = entry;\n                    }\n\n                    if (seen && heard)\n                        break;\n                }\n\n            if (seen && heard)\n                break;\n        }\n\n        if (seen) {\n            IPPTsPng *ippts = seen->seen_family == AF_INET ? &seen->client.assoc4 : &seen->client.assoc6;\n\n            LOGGER_DEBUG(\"[%u] => S[%s...] %s:%u\", (uint32_t)(candidate % assoc->candidates_bucket_count),\n                         idpart2str(seen->client.public_key, 8), ip_ntoa(&ippts->ip_port.ip), htons(ippts->ip_port.port));\n\n            DHT_getnodes(dht, &ippts->ip_port, seen->client.public_key, target_id);\n            seen->getnodes = unix_time();\n        }\n\n        if (heard && (heard != seen)) {\n            IP_Port *ipp = heard->heard_family == AF_INET ? &heard->assoc_heard4 : &heard->assoc_heard6;\n\n            LOGGER_DEBUG(\"[%u] => H[%s...] %s:%u\", (uint32_t)(candidate % assoc->candidates_bucket_count),\n                         idpart2str(heard->client.public_key, 8), ip_ntoa(&ipp->ip), htons(ipp->port));\n\n            DHT_getnodes(dht, ipp, heard->client.public_key, target_id);\n            heard->getnodes = unix_time();\n        }\n\n        LOGGER_SCOPE (\n\n            if ( !heard && !seen )\n            LOGGER_DEBUG(\"[%u] => no nodes to talk to??\", (uint32_t)(candidate % assoc->candidates_bucket_count));\n        );\n    }\n}\n\n/* destroy */\nvoid kill_Assoc(Assoc *assoc)\n{\n    if (assoc) {\n        free(assoc->candidates->list);\n        free(assoc->candidates);\n        free(assoc);\n    }\n}\n\n#ifdef TOX_LOGGER\n\nstatic char buffer[crypto_box_PUBLICKEYBYTES * 2 + 1];\nstatic char *idpart2str(uint8_t *id, size_t len)\n{\n    if (len > crypto_box_PUBLICKEYBYTES)\n        len = crypto_box_PUBLICKEYBYTES;\n\n    size_t i;\n\n    for (i = 0; i < len; i++)\n        sprintf(buffer + i * 2, \"%02hhx\", id[i]);\n\n    buffer[len * 2] = 0;\n    return buffer;\n}\n\nvoid Assoc_status(const Assoc *assoc)\n{\n    if (!assoc) {\n        LOGGER_TRACE(\"Assoc status: no assoc\");\n        return;\n    }\n\n    LOGGER_TRACE(\"[b:p] hash => [id...] used, seen, heard\");\n\n    size_t bid, cid, total = 0;\n\n    for (bid = 0; bid < assoc->candidates_bucket_count; bid++) {\n        candidates_bucket *bucket = &assoc->candidates[bid];\n\n        for (cid = 0; cid < assoc->candidates_bucket_size; cid++) {\n            Client_entry *entry = &bucket->list[cid];\n\n            if (entry->hash) {\n                total++;\n\n                LOGGER_TRACE(\"[%3i:%3i] %08x => [%s...] %i, %i(%c), %i(%c)\\n\",\n                             (int)bid, (int)cid, entry->hash, idpart2str(entry->client.public_key, 8),\n                             entry->used_at ? (int)(unix_time() - entry->used_at) : 0,\n                             entry->seen_at ? (int)(unix_time() - entry->seen_at) : 0,\n                             entry->seen_at ? (entry->seen_family == AF_INET ? '4' : (entry->seen_family == AF_INET6 ? '6' : '?')) : '?',\n                             entry->heard_at ? (int)(unix_time() - entry->heard_at) : 0,\n                             entry->heard_at ? (entry->heard_family == AF_INET ? '4' : (entry->heard_family == AF_INET6 ? '6' : '?')) : '?');\n            }\n        }\n    }\n\n    if (total) {\n        LOGGER_TRACE(\"Total: %i entries, table usage %i%%.\\n\", (int)total,\n                     (int)(total * 100 / (assoc->candidates_bucket_count * assoc->candidates_bucket_size)));\n    }\n}\n\n#endif /* TOX_LOGGER */\n"
  },
  {
    "path": "toxcore/assoc.h",
    "content": "\n#ifndef __ASSOC_H__\n#define __ASSOC_H__\n\n/* used by rendezvous */\n#define ASSOC_AVAILABLE\n\n/* For the legalese parts, see tox.h. */\n\n/* enumerated lists are superior to magic numbers */\nenum NODE_STATUS { BAD, SEENB_HEARDG, SEENG, USED };\n\n/*\n * Module to store currently unused ID <=> IP associations\n * for a potential future use\n */\n\ntypedef struct Assoc Assoc;\n\n/*****************************************************************************/\n\n/* custom distance handler, if it's not ID-distance based\n * return values exactly like id_closest() */\ntypedef int (*Assoc_distance_relative_callback)(const Assoc *assoc, void *callback_data, const uint8_t *client_id,\n        const uint8_t *client_id1, const uint8_t *client_id2);\n\n#define DISTANCE_INDEX_DISTANCE_BITS 44\n\n/* absolute distance: can be same for different client_id_check values\n * return value should have DISTANCE_INDEX_DISTANCE_BITS valid bits */\ntypedef uint64_t (*Assoc_distance_absolute_callback)(const Assoc *assoc, void *callback_data,\n        const uint8_t *client_id_ref, const uint8_t *client_id_check);\n\n/*****************************************************************************/\n\n/* Central entry point for new associations: add a new candidate to the cache\n * returns 1 if entry is stored, 2 if existing entry was updated, 0 else */\nuint8_t Assoc_add_entry(Assoc *assoc, const uint8_t *id, const IPPTs *ippts_send, const IP_Port *ipp_recv,\n                        uint8_t used);\n\n/*****************************************************************************/\n\ntypedef enum AssocCloseEntriesFlags {\n    ProtoIPv4 = 1,\n    ProtoIPv6 = 2,\n    LANOk     = 4,\n} AssocCloseEntriesFlags;\n\ntypedef struct Assoc_close_entries {\n    void                              *custom_data;        /* given to distance functions */\n    uint8_t                           *wanted_id;          /* the target client_id */\n    uint8_t                            flags;              /* additional flags */\n\n    Assoc_distance_relative_callback   distance_relative_func;\n    Assoc_distance_absolute_callback   distance_absolute_func;\n\n    uint8_t                            count_good;   /* that many should be \"good\" w.r.t. timeout */\n    uint8_t                            count;        /* allocated number of close_indices */\n    Client_data                      **result;\n} Assoc_close_entries;\n\n/* find up to close_count nodes to put into close_nodes_used of ID_Nodes\n * the distance functions can be NULL, then standard distance functions will be used\n * the caller is responsible for allocating close_indices of sufficient size\n *\n * returns 0 on error\n * returns the number of found nodes and the list of indices usable by Assoc_client()\n *    the caller is assumed to be registered from Assoc_register_callback()\n *    if they aren't, they should copy the Client_data and call Assoc_client_drop()\n */\nuint8_t Assoc_get_close_entries(Assoc *assoc, Assoc_close_entries *close_entries);\n\n/*****************************************************************************/\n\n/* create: default sizes (6, 5 => 320 entries) */\nAssoc *new_Assoc_default(const uint8_t *public_id);\n\n/* create: customized sizes\n * total is (2^bits) * entries\n * bits should be between 2 and 15 (else it's trimmed)\n * entries will be reduced to the closest prime smaller or equal\n *\n * preferably bits should be large and entries small to ensure spread\n * in the search space (e. g. 5, 5 is preferable to 2, 41) */\nAssoc *new_Assoc(size_t bits, size_t entries, const uint8_t *public_id);\n\n/* public_id changed (loaded), update which entry isn't stored */\nvoid Assoc_self_client_id_changed(Assoc *assoc, const uint8_t *public_id);\n\n/* every 45s send out a getnodes() for a \"random\" bucket */\n#define ASSOC_BUCKET_REFRESH 45\n\n/* refresh bucket's data from time to time\n * this must be called only from DHT */\nvoid do_Assoc(Assoc *assoc, DHT *dht);\n\n/* destroy */\nvoid kill_Assoc(Assoc *assoc);\n\n#ifdef TOX_LOGGER\nvoid Assoc_status(const Assoc *assoc);\n#endif /* TOX_LOGGER */\n\n#endif /* !__ASSOC_H__ */\n"
  },
  {
    "path": "toxcore/crypto_core.c",
    "content": "/* net_crypto.c\n *\n * Functions for the core crypto.\n *\n * NOTE: This code has to be perfect. We don't mess around with encryption.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"crypto_core.h\"\n\n#if crypto_box_PUBLICKEYBYTES != 32\n#error crypto_box_PUBLICKEYBYTES is required to be 32 bytes for public_key_cmp to work,\n#endif\n\n/* compare 2 public keys of length crypto_box_PUBLICKEYBYTES, not vulnerable to timing attacks.\n   returns 0 if both mem locations of length are equal,\n   return -1 if they are not. */\nint public_key_cmp(const uint8_t *pk1, const uint8_t *pk2)\n{\n    return crypto_verify_32(pk1, pk2);\n}\n\n/*  return a random number.\n */\nuint32_t random_int(void)\n{\n    uint32_t randnum;\n    randombytes((uint8_t *)&randnum , sizeof(randnum));\n    return randnum;\n}\n\nuint64_t random_64b(void)\n{\n    uint64_t randnum;\n    randombytes((uint8_t *)&randnum, sizeof(randnum));\n    return randnum;\n}\n\n/* Check if a Tox public key crypto_box_PUBLICKEYBYTES is valid or not.\n * This should only be used for input validation.\n *\n * return 0 if it isn't.\n * return 1 if it is.\n */\nint public_key_valid(const uint8_t *public_key)\n{\n    if (public_key[31] >= 128) /* Last bit of key is always zero. */\n        return 0;\n\n    return 1;\n}\n\n/* Precomputes the shared key from their public_key and our secret_key.\n * This way we can avoid an expensive elliptic curve scalar multiply for each\n * encrypt/decrypt operation.\n * enc_key has to be crypto_box_BEFORENMBYTES bytes long.\n */\nvoid encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *enc_key)\n{\n    crypto_box_beforenm(enc_key, public_key, secret_key);\n}\n\nint encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain, uint32_t length,\n                           uint8_t *encrypted)\n{\n    if (length == 0 || !secret_key || !nonce || !plain || !encrypted)\n        return -1;\n\n    uint8_t temp_plain[length + crypto_box_ZEROBYTES];\n    uint8_t temp_encrypted[length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES];\n\n    memset(temp_plain, 0, crypto_box_ZEROBYTES);\n    memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes.\n\n    if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, secret_key) != 0)\n        return -1;\n\n    /* Unpad the encrypted message. */\n    memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES);\n    return length + crypto_box_MACBYTES;\n}\n\nint decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *encrypted, uint32_t length,\n                           uint8_t *plain)\n{\n    if (length <= crypto_box_BOXZEROBYTES || !secret_key || !nonce || !encrypted || !plain)\n        return -1;\n\n    uint8_t temp_plain[length + crypto_box_ZEROBYTES];\n    uint8_t temp_encrypted[length + crypto_box_BOXZEROBYTES];\n\n    memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES);\n    memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes.\n\n    if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce, secret_key) != 0)\n        return -1;\n\n    memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES);\n    return length - crypto_box_MACBYTES;\n}\n\nint encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,\n                 const uint8_t *plain, uint32_t length, uint8_t *encrypted)\n{\n    if (!public_key || !secret_key)\n        return -1;\n\n    uint8_t k[crypto_box_BEFORENMBYTES];\n    encrypt_precompute(public_key, secret_key, k);\n    int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted);\n    sodium_memzero(k, sizeof k);\n    return ret;\n}\n\nint decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,\n                 const uint8_t *encrypted, uint32_t length, uint8_t *plain)\n{\n    if (!public_key || !secret_key)\n        return -1;\n\n    uint8_t k[crypto_box_BEFORENMBYTES];\n    encrypt_precompute(public_key, secret_key, k);\n    int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain);\n    sodium_memzero(k, sizeof k);\n    return ret;\n}\n\n\n/* Increment the given nonce by 1. */\nvoid increment_nonce(uint8_t *nonce)\n{\n    /* FIXME use increment_nonce_number(nonce, 1) or sodium_increment (change to little endian)\n     * NOTE don't use breaks inside this loop\n     * In particular, make sure, as far as possible,\n     * that loop bounds and their potential underflow or overflow\n     * are independent of user-controlled input (you may have heard of the Heartbleed bug).\n     */\n    uint32_t i = crypto_box_NONCEBYTES;\n    uint_fast16_t carry = 1U;\n\n    for (; i != 0; --i) {\n        carry += (uint_fast16_t) nonce[i - 1];\n        nonce[i - 1] = (uint8_t) carry;\n        carry >>= 8;\n    }\n}\n/* increment the given nonce by num */\nvoid increment_nonce_number(uint8_t *nonce, uint32_t host_order_num)\n{\n    /* NOTE don't use breaks inside this loop\n     * In particular, make sure, as far as possible,\n     * that loop bounds and their potential underflow or overflow\n     * are independent of user-controlled input (you may have heard of the Heartbleed bug).\n     */\n    const uint32_t big_endian_num = htonl(host_order_num);\n    const uint8_t *const num_vec = (const uint8_t *) &big_endian_num;\n    uint8_t num_as_nonce[crypto_box_NONCEBYTES] = {0};\n    num_as_nonce[crypto_box_NONCEBYTES - 4] = num_vec[0];\n    num_as_nonce[crypto_box_NONCEBYTES - 3] = num_vec[1];\n    num_as_nonce[crypto_box_NONCEBYTES - 2] = num_vec[2];\n    num_as_nonce[crypto_box_NONCEBYTES - 1] = num_vec[3];\n\n    uint32_t i = crypto_box_NONCEBYTES;\n    uint_fast16_t carry = 0U;\n\n    for (; i != 0; --i) {\n        carry += (uint_fast16_t) nonce[i - 1] + (uint_fast16_t) num_as_nonce[i - 1];\n        nonce[i - 1] = (unsigned char) carry;\n        carry >>= 8;\n    }\n}\n\n/* Fill the given nonce with random bytes. */\nvoid random_nonce(uint8_t *nonce)\n{\n    randombytes(nonce, crypto_box_NONCEBYTES);\n}\n\n/* Fill a key crypto_box_KEYBYTES big with random bytes */\nvoid new_symmetric_key(uint8_t *key)\n{\n    randombytes(key, crypto_box_KEYBYTES);\n}\n\n/* Gives a nonce guaranteed to be different from previous ones.*/\nvoid new_nonce(uint8_t *nonce)\n{\n    random_nonce(nonce);\n}\n\n/* Create a request to peer.\n * send_public_key and send_secret_key are the pub/secret keys of the sender.\n * recv_public_key is public key of receiver.\n * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big.\n * Data represents the data we send with the request with length being the length of the data.\n * request_id is the id of the request (32 = friend request, 254 = ping request).\n *\n *  return -1 on failure.\n *  return the length of the created packet on success.\n */\nint create_request(const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet,\n                   const uint8_t *recv_public_key, const uint8_t *data, uint32_t length, uint8_t request_id)\n{\n    if (!send_public_key || !packet || !recv_public_key || !data)\n        return -1;\n\n    if (MAX_CRYPTO_REQUEST_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 +\n            crypto_box_MACBYTES)\n        return -1;\n\n    uint8_t *nonce = packet + 1 + crypto_box_PUBLICKEYBYTES * 2;\n    new_nonce(nonce);\n    uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; // FIXME sodium_memzero before exit function\n    memcpy(temp + 1, data, length);\n    temp[0] = request_id;\n    int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1,\n                           1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet);\n\n    if (len == -1)\n        return -1;\n\n    packet[0] = NET_PACKET_CRYPTO;\n    memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES);\n\n    return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES;\n}\n\n/* Puts the senders public key in the request in public_key, the data from the request\n * in data if a friend or ping request was sent to us and returns the length of the data.\n * packet is the request packet and length is its length.\n *\n *  return -1 if not valid request.\n */\nint handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,\n                   uint8_t *request_id, const uint8_t *packet, uint16_t length)\n{\n    if (!self_public_key || !public_key || !data || !request_id || !packet)\n        return -1;\n\n    if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES ||\n            length > MAX_CRYPTO_REQUEST_SIZE)\n        return -1;\n\n    if (public_key_cmp(packet + 1, self_public_key) != 0)\n        return -1;\n\n    memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);\n    const uint8_t *nonce = packet + 1 + crypto_box_PUBLICKEYBYTES * 2;\n    uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; // FIXME sodium_memzero before exit function\n    int len1 = decrypt_data(public_key, self_secret_key, nonce,\n                            packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES,\n                            length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp);\n\n    if (len1 == -1 || len1 == 0)\n        return -1;\n\n    request_id[0] = temp[0];\n    --len1;\n    memcpy(data, temp + 1, len1);\n    return len1;\n}\n"
  },
  {
    "path": "toxcore/crypto_core.h",
    "content": "/* crypto_core.h\n *\n * Functions for the core crypto.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n#ifndef CORE_CRYPTO_H\n#define CORE_CRYPTO_H\n\n#include \"network.h\"\n\n#ifndef VANILLA_NACL\n/* We use libsodium by default. */\n#include <sodium.h>\n#else\n#include <crypto_box.h>\n#include <randombytes.h>\n#include <crypto_hash_sha256.h>\n#include <crypto_hash_sha512.h>\n#include <crypto_verify_16.h>\n#include <crypto_verify_32.h>\n#include <crypto_scalarmult_curve25519.h>\n#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)\n/* I know */\n#define sodium_memcmp(a, b, c) memcmp(a, b, c)\n#define sodium_memzero(a, c) memset(a, 0, c)\n#endif\n\n#define crypto_box_KEYBYTES (crypto_box_BEFORENMBYTES)\n\n/* compare 2 public keys of length crypto_box_PUBLICKEYBYTES, not vulnerable to timing attacks.\n   returns 0 if both mem locations of length are equal,\n   return -1 if they are not. */\nint public_key_cmp(const uint8_t *pk1, const uint8_t *pk2);\n\n/*  return a random number.\n *\n * random_int for a 32bin int.\n * random_64b for a 64bit int.\n */\nuint32_t random_int(void);\nuint64_t random_64b(void);\n\n/* Check if a Tox public key crypto_box_PUBLICKEYBYTES is valid or not.\n * This should only be used for input validation.\n *\n * return 0 if it isn't.\n * return 1 if it is.\n */\nint public_key_valid(const uint8_t *public_key);\n\n/* Encrypts plain of length length to encrypted of length + 16 using the\n * public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce.\n *\n *  return -1 if there was a problem.\n *  return length of encrypted data if everything was fine.\n */\nint encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,\n                 const uint8_t *plain, uint32_t length, uint8_t *encrypted);\n\n\n/* Decrypts encrypted of length length to plain of length length - 16 using the\n * public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce.\n *\n *  return -1 if there was a problem (decryption failed).\n *  return length of plain data if everything was fine.\n */\nint decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce,\n                 const uint8_t *encrypted, uint32_t length, uint8_t *plain);\n\n/* Fast encrypt/decrypt operations. Use if this is not a one-time communication.\n   encrypt_precompute does the shared-key generation once so it does not have\n   to be preformed on every encrypt/decrypt. */\nvoid encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *enc_key);\n\n/* Encrypts plain of length length to encrypted of length + 16 using a\n * secret key crypto_box_KEYBYTES big and a 24 byte nonce.\n *\n *  return -1 if there was a problem.\n *  return length of encrypted data if everything was fine.\n */\nint encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain, uint32_t length,\n                           uint8_t *encrypted);\n\n/* Decrypts encrypted of length length to plain of length length - 16 using a\n * secret key crypto_box_KEYBYTES big and a 24 byte nonce.\n *\n *  return -1 if there was a problem (decryption failed).\n *  return length of plain data if everything was fine.\n */\nint decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *encrypted, uint32_t length,\n                           uint8_t *plain);\n\n/* Increment the given nonce by 1. */\nvoid increment_nonce(uint8_t *nonce);\n\n/* increment the given nonce by num */\nvoid increment_nonce_number(uint8_t *nonce, uint32_t host_order_num);\n\n/* Fill the given nonce with random bytes. */\nvoid random_nonce(uint8_t *nonce);\n\n/* Fill a key crypto_box_KEYBYTES big with random bytes */\nvoid new_symmetric_key(uint8_t *key);\n\n/*Gives a nonce guaranteed to be different from previous ones.*/\nvoid new_nonce(uint8_t *nonce);\n\n#define MAX_CRYPTO_REQUEST_SIZE 1024\n\n#define CRYPTO_PACKET_FRIEND_REQ    32  /* Friend request crypto packet ID. */\n#define CRYPTO_PACKET_HARDENING     48  /* Hardening crypto packet ID. */\n#define CRYPTO_PACKET_DHTPK         156\n#define CRYPTO_PACKET_NAT_PING      254 /* NAT ping crypto packet ID. */\n\n/* Create a request to peer.\n * send_public_key and send_secret_key are the pub/secret keys of the sender.\n * recv_public_key is public key of receiver.\n * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big.\n * Data represents the data we send with the request with length being the length of the data.\n * request_id is the id of the request (32 = friend request, 254 = ping request).\n *\n * return -1 on failure.\n * return the length of the created packet on success.\n */\nint create_request(const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet,\n                   const uint8_t *recv_public_key, const uint8_t *data, uint32_t length, uint8_t request_id);\n\n/* puts the senders public key in the request in public_key, the data from the request\n   in data if a friend or ping request was sent to us and returns the length of the data.\n   packet is the request packet and length is its length\n   return -1 if not valid request. */\nint handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,\n                   uint8_t *request_id, const uint8_t *packet, uint16_t length);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/friend_connection.c",
    "content": "/* friend_connection.c\n *\n * Connection to friends.\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"friend_connection.h\"\n#include \"util.h\"\n\n/* return 1 if the friendcon_id is not valid.\n * return 0 if the friendcon_id is valid.\n */\nstatic uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id)\n{\n    if ((unsigned int)friendcon_id >= fr_c->num_cons)\n        return 1;\n\n    if (fr_c->conns == NULL)\n        return 1;\n\n    if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE)\n        return 1;\n\n    return 0;\n}\n\n\n/* Set the size of the friend connections list to num.\n *\n *  return -1 if realloc fails.\n *  return 0 if it succeeds.\n */\nstatic int realloc_friendconns(Friend_Connections *fr_c, uint32_t num)\n{\n    if (num == 0) {\n        free(fr_c->conns);\n        fr_c->conns = NULL;\n        return 0;\n    }\n\n    Friend_Conn *newgroup_cons = realloc(fr_c->conns, num * sizeof(Friend_Conn));\n\n    if (newgroup_cons == NULL)\n        return -1;\n\n    fr_c->conns = newgroup_cons;\n    return 0;\n}\n\n/* Create a new empty friend connection.\n *\n * return -1 on failure.\n * return friendcon_id on success.\n */\nstatic int create_friend_conn(Friend_Connections *fr_c)\n{\n    uint32_t i;\n\n    for (i = 0; i < fr_c->num_cons; ++i) {\n        if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE)\n            return i;\n    }\n\n    int id = -1;\n\n    if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) {\n        id = fr_c->num_cons;\n        ++fr_c->num_cons;\n        memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn));\n    }\n\n    return id;\n}\n\n/* Wipe a friend connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id)\n{\n    if (friendconn_id_not_valid(fr_c, friendcon_id))\n        return -1;\n\n    uint32_t i;\n    memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn));\n\n    for (i = fr_c->num_cons; i != 0; --i) {\n        if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE)\n            break;\n    }\n\n    if (fr_c->num_cons != i) {\n        fr_c->num_cons = i;\n        realloc_friendconns(fr_c, fr_c->num_cons);\n    }\n\n    return 0;\n}\n\nstatic Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id)\n{\n    if (friendconn_id_not_valid(fr_c, friendcon_id))\n        return 0;\n\n    return &fr_c->conns[friendcon_id];\n}\n\n/* return friendcon_id corresponding to the real public key on success.\n * return -1 on failure.\n */\nint getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk)\n{\n    uint32_t i;\n\n    for (i = 0; i < fr_c->num_cons; ++i) {\n        Friend_Conn *friend_con = get_conn(fr_c, i);\n\n        if (friend_con) {\n            if (public_key_cmp(friend_con->real_public_key, real_pk) == 0)\n                return i;\n        }\n    }\n\n    return -1;\n}\n\n/* Add a TCP relay associated to the friend.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    /* Local ip and same pk means that they are hosting a TCP relay. */\n    if (Local_ip(ip_port.ip) && public_key_cmp(friend_con->dht_temp_pk, public_key) == 0) {\n        if (friend_con->dht_ip_port.ip.family != 0) {\n            ip_port.ip = friend_con->dht_ip_port.ip;\n        } else {\n            friend_con->hosting_tcp_relay = 0;\n        }\n    }\n\n    unsigned int i;\n\n    uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS;\n\n    for (i = 0; i < FRIEND_MAX_STORED_TCP_RELAYS; ++i) {\n        if (friend_con->tcp_relays[i].ip_port.ip.family != 0\n                && public_key_cmp(friend_con->tcp_relays[i].public_key, public_key) == 0) {\n            memset(&friend_con->tcp_relays[i], 0, sizeof(Node_format));\n        }\n    }\n\n    friend_con->tcp_relays[index].ip_port = ip_port;\n    memcpy(friend_con->tcp_relays[index].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    ++friend_con->tcp_relay_counter;\n\n    return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key);\n}\n\n/* Connect to number saved relays for friend. */\nstatic void connect_to_saved_tcp_relays(Friend_Connections *fr_c, int friendcon_id, unsigned int number)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return;\n\n    unsigned int i;\n\n    for (i = 0; (i < FRIEND_MAX_STORED_TCP_RELAYS) && (number != 0); ++i) {\n        uint16_t index = (friend_con->tcp_relay_counter - (i + 1)) % FRIEND_MAX_STORED_TCP_RELAYS;\n\n        if (friend_con->tcp_relays[index].ip_port.ip.family) {\n            if (add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->tcp_relays[index].ip_port,\n                                   friend_con->tcp_relays[index].public_key) == 0) {\n                --number;\n            }\n        }\n    }\n}\n\nstatic unsigned int send_relays(Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return 0;\n\n    Node_format nodes[MAX_SHARED_RELAYS];\n    uint8_t data[1024];\n    int n, length;\n\n    n = copy_connected_tcp_relays(fr_c->net_crypto, nodes, MAX_SHARED_RELAYS);\n\n    int i;\n\n    for (i = 0; i < n; ++i) {\n        /* Associated the relays being sent with this connection.\n           On receiving the peer will do the same which will establish the connection. */\n        friend_add_tcp_relay(fr_c, friendcon_id, nodes[i].ip_port, nodes[i].public_key);\n    }\n\n    length = pack_nodes(data + 1, sizeof(data) - 1, nodes, n);\n\n    if (length <= 0)\n        return 0;\n\n    data[0] = PACKET_ID_SHARE_RELAYS;\n    ++length;\n\n    if (write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, data, length, 0) != -1) {\n        friend_con->share_relays_lastsent = unix_time();\n        return 1;\n    }\n\n    return 0;\n}\n\n/* callback for recv TCP relay nodes. */\nstatic int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key)\n{\n    Friend_Connections *fr_c = object;\n    Friend_Conn *friend_con = get_conn(fr_c, number);\n\n    if (!friend_con)\n        return -1;\n\n    if (friend_con->crypt_connection_id != -1) {\n        return friend_add_tcp_relay(fr_c, number, ip_port, public_key);\n    } else {\n        return add_tcp_relay(fr_c->net_crypto, ip_port, public_key);\n    }\n}\n\nstatic int friend_new_connection(Friend_Connections *fr_c, int friendcon_id);\n/* Callback for DHT ip_port changes. */\nstatic void dht_ip_callback(void *object, int32_t number, IP_Port ip_port)\n{\n    Friend_Connections *fr_c = object;\n    Friend_Conn *friend_con = get_conn(fr_c, number);\n\n    if (!friend_con)\n        return;\n\n    if (friend_con->crypt_connection_id == -1) {\n        friend_new_connection(fr_c, number);\n    }\n\n    set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, 1);\n    friend_con->dht_ip_port = ip_port;\n    friend_con->dht_ip_port_lastrecv = unix_time();\n\n    if (friend_con->hosting_tcp_relay) {\n        friend_add_tcp_relay(fr_c, number, ip_port, friend_con->dht_temp_pk);\n        friend_con->hosting_tcp_relay = 0;\n    }\n}\n\nstatic void change_dht_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_public_key)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return;\n\n    friend_con->dht_pk_lastrecv = unix_time();\n\n    if (friend_con->dht_lock) {\n        if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) {\n            printf(\"a. Could not delete dht peer. Please report this.\\n\");\n            return;\n        }\n\n        friend_con->dht_lock = 0;\n    }\n\n    DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, fr_c, friendcon_id, &friend_con->dht_lock);\n    memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES);\n}\n\nstatic int handle_status(void *object, int number, uint8_t status)\n{\n    Friend_Connections *fr_c = object;\n    Friend_Conn *friend_con = get_conn(fr_c, number);\n\n    if (!friend_con)\n        return -1;\n\n    _Bool call_cb = 0;\n\n    if (status) {  /* Went online. */\n        call_cb = 1;\n        friend_con->status = FRIENDCONN_STATUS_CONNECTED;\n        friend_con->ping_lastrecv = unix_time();\n        friend_con->share_relays_lastsent = 0;\n        onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status);\n    } else {  /* Went offline. */\n        if (friend_con->status != FRIENDCONN_STATUS_CONNECTING) {\n            call_cb = 1;\n            friend_con->dht_pk_lastrecv = unix_time();\n            onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status);\n        }\n\n        friend_con->status = FRIENDCONN_STATUS_CONNECTING;\n        friend_con->crypt_connection_id = -1;\n        friend_con->hosting_tcp_relay = 0;\n    }\n\n    if (call_cb) {\n        unsigned int i;\n\n        for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {\n            if (friend_con->callbacks[i].status_callback)\n                friend_con->callbacks[i].status_callback(friend_con->callbacks[i].status_callback_object,\n                        friend_con->callbacks[i].status_callback_id, status);\n        }\n    }\n\n    return 0;\n}\n\n/* Callback for dht public key changes. */\nstatic void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key)\n{\n    Friend_Connections *fr_c = object;\n    Friend_Conn *friend_con = get_conn(fr_c, number);\n\n    if (!friend_con)\n        return;\n\n    if (public_key_cmp(friend_con->dht_temp_pk, dht_public_key) == 0)\n        return;\n\n    change_dht_pk(fr_c, number, dht_public_key);\n\n    /* if pk changed, create a new connection.*/\n    if (friend_con->crypt_connection_id != -1) {\n        crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id);\n        friend_con->crypt_connection_id = -1;\n        handle_status(object, number, 0); /* Going offline. */\n    }\n\n    friend_new_connection(fr_c, number);\n    onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key);\n}\n\nstatic int handle_packet(void *object, int number, uint8_t *data, uint16_t length)\n{\n    if (length == 0)\n        return -1;\n\n    Friend_Connections *fr_c = object;\n    Friend_Conn *friend_con = get_conn(fr_c, number);\n\n    if (!friend_con)\n        return -1;\n\n    if (data[0] == PACKET_ID_FRIEND_REQUESTS) {\n        if (fr_c->fr_request_callback)\n            fr_c->fr_request_callback(fr_c->fr_request_object, friend_con->real_public_key, data, length);\n\n        return 0;\n    } else if (data[0] == PACKET_ID_ALIVE) {\n        friend_con->ping_lastrecv = unix_time();\n        return 0;\n    } else if (data[0] == PACKET_ID_SHARE_RELAYS) {\n        Node_format nodes[MAX_SHARED_RELAYS];\n        int n;\n\n        if ((n = unpack_nodes(nodes, MAX_SHARED_RELAYS, NULL, data + 1, length - 1, 1)) == -1)\n            return -1;\n\n        int j;\n\n        for (j = 0; j < n; j++) {\n            friend_add_tcp_relay(fr_c, number, nodes[j].ip_port, nodes[j].public_key);\n        }\n\n        return 0;\n    }\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {\n        if (friend_con->callbacks[i].data_callback)\n            friend_con->callbacks[i].data_callback(friend_con->callbacks[i].data_callback_object,\n                                                   friend_con->callbacks[i].data_callback_id, data, length);\n\n        friend_con = get_conn(fr_c, number);\n\n        if (!friend_con)\n            return -1;\n    }\n\n    return 0;\n}\n\nstatic int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length)\n{\n    if (length == 0)\n        return -1;\n\n    Friend_Connections *fr_c = object;\n    Friend_Conn *friend_con = get_conn(fr_c, number);\n\n    if (!friend_con)\n        return -1;\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) {\n        if (friend_con->callbacks[i].lossy_data_callback)\n            friend_con->callbacks[i].lossy_data_callback(friend_con->callbacks[i].lossy_data_callback_object,\n                    friend_con->callbacks[i].lossy_data_callback_id, data, length);\n\n        friend_con = get_conn(fr_c, number);\n\n        if (!friend_con)\n            return -1;\n    }\n\n    return 0;\n}\n\nstatic int handle_new_connections(void *object, New_Connection *n_c)\n{\n    Friend_Connections *fr_c = object;\n    int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key);\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (friend_con) {\n\n        if (friend_con->crypt_connection_id != -1)\n            return -1;\n\n        int id = accept_crypto_connection(fr_c->net_crypto, n_c);\n\n        if (id == -1) {\n            return -1;\n        }\n\n        connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id);\n        connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id);\n        connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id);\n        friend_con->crypt_connection_id = id;\n\n        if (n_c->source.ip.family != AF_INET && n_c->source.ip.family != AF_INET6) {\n            set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port, 0);\n        } else {\n            friend_con->dht_ip_port = n_c->source;\n            friend_con->dht_ip_port_lastrecv = unix_time();\n        }\n\n        if (public_key_cmp(friend_con->dht_temp_pk, n_c->dht_public_key) != 0) {\n            change_dht_pk(fr_c, friendcon_id, n_c->dht_public_key);\n        }\n\n        nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id);\n        return 0;\n    }\n\n    return -1;\n}\n\nstatic int friend_new_connection(Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    if (friend_con->crypt_connection_id != -1) {\n        return -1;\n    }\n\n    /* If dht_temp_pk does not contains a pk. */\n    if (!friend_con->dht_lock) {\n        return -1;\n    }\n\n    int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key, friend_con->dht_temp_pk);\n\n    if (id == -1)\n        return -1;\n\n    friend_con->crypt_connection_id = id;\n    connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id);\n    connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id);\n    connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id);\n    nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id);\n\n    return 0;\n}\n\nstatic int send_ping(const Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    uint8_t ping = PACKET_ID_ALIVE;\n    int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0);\n\n    if (ret != -1) {\n        friend_con->ping_lastsent = unix_time();\n        return 0;\n    }\n\n    return -1;\n}\n\n/* Increases lock_count for the connection with friendcon_id by 1.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint friend_connection_lock(Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    ++friend_con->lock_count;\n    return 0;\n}\n\n/* return FRIENDCONN_STATUS_CONNECTED if the friend is connected.\n * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected.\n * return FRIENDCONN_STATUS_NONE on failure.\n */\nunsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return 0;\n\n    return friend_con->status;\n}\n\n/* Copy public keys associated to friendcon_id.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    if (real_pk)\n        memcpy(real_pk, friend_con->real_public_key, crypto_box_PUBLICKEYBYTES);\n\n    if (dht_temp_pk)\n        memcpy(dht_temp_pk, friend_con->dht_temp_pk, crypto_box_PUBLICKEYBYTES);\n\n    return 0;\n}\n\n/* Set temp dht key for connection.\n */\nvoid set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk)\n{\n    dht_pk_callback(fr_c, friendcon_id, dht_temp_pk);\n}\n\n/* Set the callbacks for the friend connection.\n * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array.\n *\n * return 0 on success.\n * return -1 on failure\n */\nint friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index,\n                                int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data,\n                                        uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object,\n                                int number)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    if (index >= MAX_FRIEND_CONNECTION_CALLBACKS)\n        return -1;\n\n    friend_con->callbacks[index].status_callback = status_callback;\n    friend_con->callbacks[index].data_callback = data_callback;\n    friend_con->callbacks[index].lossy_data_callback = lossy_data_callback;\n\n    friend_con->callbacks[index].status_callback_object =\n        friend_con->callbacks[index].data_callback_object =\n            friend_con->callbacks[index].lossy_data_callback_object = object;\n\n    friend_con->callbacks[index].status_callback_id =\n        friend_con->callbacks[index].data_callback_id =\n            friend_con->callbacks[index].lossy_data_callback_id = number;\n    return 0;\n}\n\n/* return the crypt_connection_id for the connection.\n *\n * return crypt_connection_id on success.\n * return -1 on failure.\n */\nint friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    return friend_con->crypt_connection_id;\n}\n\n/* Create a new friend connection.\n * If one to that real public key already exists, increase lock count and return it.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nint new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key)\n{\n    int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key);\n\n    if (friendcon_id != -1) {\n        ++fr_c->conns[friendcon_id].lock_count;\n        return friendcon_id;\n    }\n\n    friendcon_id = create_friend_conn(fr_c);\n\n    if (friendcon_id == -1)\n        return -1;\n\n    int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key);\n\n    if (onion_friendnum == -1)\n        return -1;\n\n    Friend_Conn *friend_con = &fr_c->conns[friendcon_id];\n\n    friend_con->crypt_connection_id = -1;\n    friend_con->status = FRIENDCONN_STATUS_CONNECTING;\n    memcpy(friend_con->real_public_key, real_public_key, crypto_box_PUBLICKEYBYTES);\n    friend_con->onion_friendnum = onion_friendnum;\n\n    recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id);\n    onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id);\n\n    return friendcon_id;\n}\n\n/* Kill a friend connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint kill_friend_connection(Friend_Connections *fr_c, int friendcon_id)\n{\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    if (friend_con->lock_count) {\n        --friend_con->lock_count;\n        return 0;\n    }\n\n    onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum);\n    crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id);\n\n    if (friend_con->dht_lock) {\n        DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock);\n    }\n\n    return wipe_friend_conn(fr_c, friendcon_id);\n}\n\n\n/* Set friend request callback.\n *\n * This function will be called every time a friend request packet is received.\n */\nvoid set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *,\n                                 const uint8_t *, uint16_t), void *object)\n{\n    fr_c->fr_request_callback = fr_request_callback;\n    fr_c->fr_request_object = object;\n    oniondata_registerhandler(fr_c->onion_c, CRYPTO_PACKET_FRIEND_REQ, fr_request_callback, object);\n}\n\n/* Send a Friend request packet.\n *\n *  return -1 if failure.\n *  return  0 if it sent the friend request directly to the friend.\n *  return the number of peers it was routed through if it did not send it directly.\n */\nint send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data,\n                               uint16_t length)\n{\n    if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0)\n        return -1;\n\n    Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);\n\n    if (!friend_con)\n        return -1;\n\n    uint8_t packet[1 + sizeof(nospam_num) + length];\n    memcpy(packet + 1, &nospam_num, sizeof(nospam_num));\n    memcpy(packet + 1 + sizeof(nospam_num), data, length);\n\n    if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) {\n        packet[0] = PACKET_ID_FRIEND_REQUESTS;\n        return write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, packet, sizeof(packet), 0) != -1;\n    } else {\n        packet[0] = CRYPTO_PACKET_FRIEND_REQ;\n        int num = send_onion_data(fr_c->onion_c, friend_con->onion_friendnum, packet, sizeof(packet));\n\n        if (num <= 0)\n            return -1;\n\n        return num;\n    }\n}\n\n/* Create new friend_connections instance. */\nFriend_Connections *new_friend_connections(Onion_Client *onion_c)\n{\n    if (!onion_c)\n        return NULL;\n\n    Friend_Connections *temp = calloc(1, sizeof(Friend_Connections));\n\n    if (temp == NULL)\n        return NULL;\n\n    temp->dht = onion_c->dht;\n    temp->net_crypto = onion_c->c;\n    temp->onion_c = onion_c;\n\n    new_connection_handler(temp->net_crypto, &handle_new_connections, temp);\n    LANdiscovery_init(temp->dht);\n\n    return temp;\n}\n\n/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */\nstatic void LANdiscovery(Friend_Connections *fr_c)\n{\n    if (fr_c->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) {\n        send_LANdiscovery(htons(TOX_PORT_DEFAULT), fr_c->dht);\n        fr_c->last_LANdiscovery = unix_time();\n    }\n}\n\n/* main friend_connections loop. */\nvoid do_friend_connections(Friend_Connections *fr_c)\n{\n    uint32_t i;\n    uint64_t temp_time = unix_time();\n\n    for (i = 0; i < fr_c->num_cons; ++i) {\n        Friend_Conn *friend_con = get_conn(fr_c, i);\n\n        if (friend_con) {\n            if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) {\n                if (friend_con->dht_pk_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) {\n                    if (friend_con->dht_lock) {\n                        DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock);\n                        friend_con->dht_lock = 0;\n                    }\n                }\n\n                if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) {\n                    friend_con->dht_ip_port.ip.family = 0;\n                }\n\n                if (friend_con->dht_lock) {\n                    if (friend_new_connection(fr_c, i) == 0) {\n                        set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port, 0);\n                        connect_to_saved_tcp_relays(fr_c, i, (MAX_FRIEND_TCP_CONNECTIONS / 2)); /* Only fill it half up. */\n                    }\n                }\n\n            } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) {\n                if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) {\n                    send_ping(fr_c, i);\n                }\n\n                if (friend_con->share_relays_lastsent + SHARE_RELAYS_INTERVAL < temp_time) {\n                    send_relays(fr_c, i);\n                }\n\n                if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) {\n                    /* If we stopped receiving ping packets, kill it. */\n                    crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id);\n                    friend_con->crypt_connection_id = -1;\n                    handle_status(fr_c, i, 0); /* Going offline. */\n                }\n            }\n        }\n    }\n\n    LANdiscovery(fr_c);\n}\n\n/* Free everything related with friend_connections. */\nvoid kill_friend_connections(Friend_Connections *fr_c)\n{\n    if (!fr_c)\n        return;\n\n    uint32_t i;\n\n    for (i = 0; i < fr_c->num_cons; ++i) {\n        kill_friend_connection(fr_c, i);\n    }\n\n    LANdiscovery_kill(fr_c->dht);\n    free(fr_c);\n}\n"
  },
  {
    "path": "toxcore/friend_connection.h",
    "content": "/* friend_connection.h\n *\n * Connection to friends.\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n\n#ifndef FRIEND_CONNECTION_H\n#define FRIEND_CONNECTION_H\n\n#include \"net_crypto.h\"\n#include \"DHT.h\"\n#include \"LAN_discovery.h\"\n#include \"onion_client.h\"\n\n\n#define MAX_FRIEND_CONNECTION_CALLBACKS 2\n#define MESSENGER_CALLBACK_INDEX 0\n#define GROUPCHAT_CALLBACK_INDEX 1\n\n#define PACKET_ID_ALIVE 16\n#define PACKET_ID_SHARE_RELAYS 17\n#define PACKET_ID_FRIEND_REQUESTS 18\n\n/* Interval between the sending of ping packets. */\n#define FRIEND_PING_INTERVAL 8\n\n/* If no packets are received from friend in this time interval, kill the connection. */\n#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 4)\n\n/* Time before friend is removed from the DHT after last hearing about him. */\n#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT\n\n#define FRIEND_MAX_STORED_TCP_RELAYS (MAX_FRIEND_TCP_CONNECTIONS * 4)\n\n/* Max number of tcp relays sent to friends */\n#define MAX_SHARED_RELAYS (RECOMMENDED_FRIEND_TCP_CONNECTIONS)\n\n/* Interval between the sending of tcp relay information */\n#define SHARE_RELAYS_INTERVAL (5 * 60)\n\n\nenum {\n    FRIENDCONN_STATUS_NONE,\n    FRIENDCONN_STATUS_CONNECTING,\n    FRIENDCONN_STATUS_CONNECTED\n};\n\ntypedef struct {\n    uint8_t status;\n\n    uint8_t real_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];\n    uint16_t dht_lock;\n    IP_Port dht_ip_port;\n    uint64_t dht_pk_lastrecv, dht_ip_port_lastrecv;\n\n    int onion_friendnum;\n    int crypt_connection_id;\n\n    uint64_t ping_lastrecv, ping_lastsent;\n    uint64_t share_relays_lastsent;\n\n    struct {\n        int (*status_callback)(void *object, int id, uint8_t status);\n        void *status_callback_object;\n        int status_callback_id;\n\n        int (*data_callback)(void *object, int id, uint8_t *data, uint16_t length);\n        void *data_callback_object;\n        int data_callback_id;\n\n        int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length);\n        void *lossy_data_callback_object;\n        int lossy_data_callback_id;\n    } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS];\n\n    uint16_t lock_count;\n\n    Node_format tcp_relays[FRIEND_MAX_STORED_TCP_RELAYS];\n    uint16_t tcp_relay_counter;\n\n    _Bool hosting_tcp_relay;\n} Friend_Conn;\n\n\ntypedef struct {\n    Net_Crypto *net_crypto;\n    DHT *dht;\n    Onion_Client *onion_c;\n\n    Friend_Conn *conns;\n    uint32_t num_cons;\n\n    int (*fr_request_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t len);\n    void *fr_request_object;\n\n    uint64_t last_LANdiscovery;\n} Friend_Connections;\n\n/* return friendcon_id corresponding to the real public key on success.\n * return -1 on failure.\n */\nint getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk);\n\n/* Increases lock_count for the connection with friendcon_id by 1.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint friend_connection_lock(Friend_Connections *fr_c, int friendcon_id);\n\n/* return FRIENDCONN_STATUS_CONNECTED if the friend is connected.\n * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected.\n * return FRIENDCONN_STATUS_NONE on failure.\n */\nunsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id);\n\n/* Copy public keys associated to friendcon_id.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id);\n\n/* Set temp dht key for connection.\n */\nvoid set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk);\n\n/* Add a TCP relay associated to the friend.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key);\n\n/* Set the callbacks for the friend connection.\n * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array.\n *\n * return 0 on success.\n * return -1 on failure\n */\nint friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index,\n                                int (*status_callback)(void *object, int id, uint8_t status), int (*data_callback)(void *object, int id, uint8_t *data,\n                                        uint16_t length), int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object,\n                                int number);\n\n/* return the crypt_connection_id for the connection.\n *\n * return crypt_connection_id on success.\n * return -1 on failure.\n */\nint friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id);\n\n/* Create a new friend connection.\n * If one to that real public key already exists, increase lock count and return it.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nint new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key);\n\n/* Kill a friend connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint kill_friend_connection(Friend_Connections *fr_c, int friendcon_id);\n\n/* Send a Friend request packet.\n *\n *  return -1 if failure.\n *  return  0 if it sent the friend request directly to the friend.\n *  return the number of peers it was routed through if it did not send it directly.\n */\nint send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data,\n                               uint16_t length);\n\n/* Set friend request callback.\n *\n * This function will be called every time a friend request is received.\n */\nvoid set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *,\n                                 const uint8_t *, uint16_t), void *object);\n\n/* Create new friend_connections instance. */\nFriend_Connections *new_friend_connections(Onion_Client *onion_c);\n\n/* main friend_connections loop. */\nvoid do_friend_connections(Friend_Connections *fr_c);\n\n/* Free everything related with friend_connections. */\nvoid kill_friend_connections(Friend_Connections *fr_c);\n\n#endif\n"
  },
  {
    "path": "toxcore/friend_requests.c",
    "content": "/* friend_requests.c\n *\n * Handle friend requests.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"friend_requests.h\"\n#include \"util.h\"\n\n\n/* Set and get the nospam variable used to prevent one type of friend request spam. */\nvoid set_nospam(Friend_Requests *fr, uint32_t num)\n{\n    fr->nospam = num;\n}\n\nuint32_t get_nospam(const Friend_Requests *fr)\n{\n    return fr->nospam;\n}\n\n\n/* Set the function that will be executed when a friend request is received. */\nvoid callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t,\n                            void *), void *object, void *userdata)\n{\n    fr->handle_friendrequest = function;\n    fr->handle_friendrequest_isset = 1;\n    fr->handle_friendrequest_object = object;\n    fr->handle_friendrequest_userdata = userdata;\n}\n/* Set the function used to check if a friend request should be displayed to the user or not. */\nvoid set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata)\n{\n    fr->filter_function = function;\n    fr->filter_function_userdata = userdata;\n}\n\n/* Add to list of received friend requests. */\nstatic void addto_receivedlist(Friend_Requests *fr, const uint8_t *real_pk)\n{\n    if (fr->received_requests_index >= MAX_RECEIVED_STORED)\n        fr->received_requests_index = 0;\n\n    id_copy(fr->received_requests[fr->received_requests_index], real_pk);\n    ++fr->received_requests_index;\n}\n\n/* Check if a friend request was already received.\n *\n *  return 0 if it did not.\n *  return 1 if it did.\n */\nstatic int request_received(Friend_Requests *fr, const uint8_t *real_pk)\n{\n    uint32_t i;\n\n    for (i = 0; i < MAX_RECEIVED_STORED; ++i)\n        if (id_equal(fr->received_requests[i], real_pk))\n            return 1;\n\n    return 0;\n}\n\n/* Remove real pk from received_requests list.\n *\n *  return 0 if it removed it successfully.\n *  return -1 if it didn't find it.\n */\nint remove_request_received(Friend_Requests *fr, const uint8_t *real_pk)\n{\n    uint32_t i;\n\n    for (i = 0; i < MAX_RECEIVED_STORED; ++i) {\n        if (id_equal(fr->received_requests[i], real_pk)) {\n            sodium_memzero(fr->received_requests[i], crypto_box_PUBLICKEYBYTES);\n            return 0;\n        }\n    }\n\n    return -1;\n}\n\n\nstatic int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint16_t length)\n{\n    Friend_Requests *fr = object;\n\n    if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE)\n        return 1;\n\n    ++packet;\n    --length;\n\n    if (fr->handle_friendrequest_isset == 0)\n        return 1;\n\n    if (request_received(fr, source_pubkey))\n        return 1;\n\n    if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0)\n        return 1;\n\n    if (fr->filter_function)\n        if ((*fr->filter_function)(source_pubkey, fr->filter_function_userdata) != 0)\n            return 1;\n\n    addto_receivedlist(fr, source_pubkey);\n\n    uint32_t message_len = length - sizeof(fr->nospam);\n    uint8_t message[message_len + 1];\n    memcpy(message, packet + sizeof(fr->nospam), message_len);\n    message[sizeof(message) - 1] = 0; /* Be sure the message is null terminated. */\n\n    (*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, message_len,\n                                fr->handle_friendrequest_userdata);\n    return 0;\n}\n\nvoid friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c)\n{\n    set_friend_request_callback(fr_c, &friendreq_handlepacket, fr);\n}\n"
  },
  {
    "path": "toxcore/friend_requests.h",
    "content": "/* friend_requests.h\n *\n * Handle friend requests.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef FRIEND_REQUESTS_H\n#define FRIEND_REQUESTS_H\n\n#include \"friend_connection.h\"\n\n#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t)))\n\ntypedef struct {\n    uint32_t nospam;\n    void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, size_t, void *);\n    uint8_t handle_friendrequest_isset;\n    void *handle_friendrequest_object;\n    void *handle_friendrequest_userdata;\n\n    int (*filter_function)(const uint8_t *, void *);\n    void *filter_function_userdata;\n    /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem.\n     *  TODO: Make this better (This will most likely tie in with the way we will handle spam.)\n     */\n\n#define MAX_RECEIVED_STORED 32\n\n    uint8_t received_requests[MAX_RECEIVED_STORED][crypto_box_PUBLICKEYBYTES];\n    uint16_t received_requests_index;\n} Friend_Requests;\n\n/* Set and get the nospam variable used to prevent one type of friend request spam. */\nvoid set_nospam(Friend_Requests *fr, uint32_t num);\nuint32_t get_nospam(const Friend_Requests *fr);\n\n/* Remove real_pk from received_requests list.\n *\n *  return 0 if it removed it successfully.\n *  return -1 if it didn't find it.\n */\nint remove_request_received(Friend_Requests *fr, const uint8_t *real_pk);\n\n/* Set the function that will be executed when a friend request for us is received.\n *  Function format is function(uint8_t * public_key, uint8_t * data, size_t length, void * userdata)\n */\nvoid callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t,\n                            void *), void *object, void *userdata);\n\n/* Set the function used to check if a friend request should be displayed to the user or not.\n * Function format is int function(uint8_t * public_key, void * userdata)\n * It must return 0 if the request is ok (anything else if it is bad.)\n */\nvoid set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata);\n\n/* Sets up friendreq packet handlers. */\nvoid friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/group.c",
    "content": "/* group.c\n *\n * Slightly better groupchats implementation.\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"group.h\"\n#include \"util.h\"\n\n/* return 1 if the groupnumber is not valid.\n * return 0 if the groupnumber is valid.\n */\nstatic uint8_t groupnumber_not_valid(const Group_Chats *g_c, int groupnumber)\n{\n    if ((unsigned int)groupnumber >= g_c->num_chats)\n        return 1;\n\n    if (g_c->chats == NULL)\n        return 1;\n\n    if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE)\n        return 1;\n\n    return 0;\n}\n\n\n/* Set the size of the groupchat list to num.\n *\n *  return -1 if realloc fails.\n *  return 0 if it succeeds.\n */\nstatic int realloc_groupchats(Group_Chats *g_c, uint32_t num)\n{\n    if (num == 0) {\n        free(g_c->chats);\n        g_c->chats = NULL;\n        return 0;\n    }\n\n    Group_c *newgroup_chats = realloc(g_c->chats, num * sizeof(Group_c));\n\n    if (newgroup_chats == NULL)\n        return -1;\n\n    g_c->chats = newgroup_chats;\n    return 0;\n}\n\n\n/* Create a new empty groupchat connection.\n *\n * return -1 on failure.\n * return groupnumber on success.\n */\nstatic int create_group_chat(Group_Chats *g_c)\n{\n    uint32_t i;\n\n    for (i = 0; i < g_c->num_chats; ++i) {\n        if (g_c->chats[i].status == GROUPCHAT_STATUS_NONE)\n            return i;\n    }\n\n    int id = -1;\n\n    if (realloc_groupchats(g_c, g_c->num_chats + 1) == 0) {\n        id = g_c->num_chats;\n        ++g_c->num_chats;\n        memset(&(g_c->chats[id]), 0, sizeof(Group_c));\n    }\n\n    return id;\n}\n\n\n/* Wipe a groupchat.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int wipe_group_chat(Group_Chats *g_c, int groupnumber)\n{\n    if (groupnumber_not_valid(g_c, groupnumber))\n        return -1;\n\n    uint32_t i;\n    sodium_memzero(&(g_c->chats[groupnumber]), sizeof(Group_c));\n\n    for (i = g_c->num_chats; i != 0; --i) {\n        if (g_c->chats[i - 1].status != GROUPCHAT_STATUS_NONE)\n            break;\n    }\n\n    if (g_c->num_chats != i) {\n        g_c->num_chats = i;\n        realloc_groupchats(g_c, g_c->num_chats);\n    }\n\n    return 0;\n}\n\nstatic Group_c *get_group_c(const Group_Chats *g_c, int groupnumber)\n{\n    if (groupnumber_not_valid(g_c, groupnumber))\n        return 0;\n\n    return &g_c->chats[groupnumber];\n}\n\n/*\n * check if peer with real_pk is in peer array.\n *\n * return peer index if peer is in chat.\n * return -1 if peer is not in chat.\n *\n * TODO: make this more efficient.\n */\n\nstatic int peer_in_chat(const Group_c *chat, const uint8_t *real_pk)\n{\n    uint32_t i;\n\n    for (i = 0; i < chat->numpeers; ++i)\n        if (id_equal(chat->group[i].real_pk, real_pk))\n            return i;\n\n    return -1;\n}\n\n/*\n * check if group with identifier is in group array.\n *\n * return group number if peer is in list.\n * return -1 if group is not in list.\n *\n * TODO: make this more efficient and maybe use constant time comparisons?\n */\nstatic int get_group_num(const Group_Chats *g_c, const uint8_t *identifier)\n{\n    uint32_t i;\n\n    for (i = 0; i < g_c->num_chats; ++i)\n        if (sodium_memcmp(g_c->chats[i].identifier, identifier, GROUP_IDENTIFIER_LENGTH) == 0)\n            return i;\n\n    return -1;\n}\n\n/*\n * check if peer with peer_number is in peer array.\n *\n * return peer number if peer is in chat.\n * return -1 if peer is not in chat.\n *\n * TODO: make this more efficient.\n */\nstatic int get_peer_index(Group_c *g, uint16_t peer_number)\n{\n    uint32_t i;\n\n    for (i = 0; i < g->numpeers; ++i)\n        if (g->group[i].peer_number == peer_number)\n            return i;\n\n    return -1;\n}\n\n\nstatic uint64_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2)\n{\n    uint64_t cmp1 = 0, cmp2 = 0;\n\n    unsigned int i;\n\n    for (i = 0; i < sizeof(uint64_t); ++i) {\n        cmp1 = (cmp1 << 8) + (uint64_t)pk1[i];\n        cmp2 = (cmp2 << 8) + (uint64_t)pk2[i];\n    }\n\n    return (cmp1 - cmp2);\n}\n\nenum {\n    GROUPCHAT_CLOSEST_NONE,\n    GROUPCHAT_CLOSEST_ADDED,\n    GROUPCHAT_CLOSEST_REMOVED\n};\n\nstatic int friend_in_close(Group_c *g, int friendcon_id);\nstatic int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock);\n\nstatic int add_to_closest(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if (public_key_cmp(g->real_pk, real_pk) == 0)\n        return -1;\n\n    unsigned int i;\n    unsigned int index = DESIRED_CLOSE_CONNECTIONS;\n\n    for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {\n        if (g->closest_peers[i].entry && public_key_cmp(real_pk, g->closest_peers[i].real_pk) == 0) {\n            return 0;\n        }\n    }\n\n    for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {\n        if (g->closest_peers[i].entry == 0) {\n            index = i;\n            break;\n        }\n    }\n\n    if (index == DESIRED_CLOSE_CONNECTIONS) {\n        uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk);\n        uint64_t comp_d = 0;\n\n        for (i = 0; i < (DESIRED_CLOSE_CONNECTIONS / 2); ++i) {\n            uint64_t comp;\n            comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk);\n\n            if (comp > comp_val && comp > comp_d) {\n                index = i;\n                comp_d = comp;\n            }\n        }\n\n        comp_val = calculate_comp_value(real_pk, g->real_pk);\n\n        for (i = (DESIRED_CLOSE_CONNECTIONS / 2); i < DESIRED_CLOSE_CONNECTIONS; ++i) {\n            uint64_t comp = calculate_comp_value(g->closest_peers[i].real_pk, g->real_pk);\n\n            if (comp > comp_val && comp > comp_d) {\n                index = i;\n                comp_d = comp;\n            }\n        }\n    }\n\n    if (index == DESIRED_CLOSE_CONNECTIONS) {\n        return -1;\n    }\n\n    uint8_t old_real_pk[crypto_box_PUBLICKEYBYTES];\n    uint8_t old_temp_pk[crypto_box_PUBLICKEYBYTES];\n    uint8_t old = 0;\n\n    if (g->closest_peers[index].entry) {\n        memcpy(old_real_pk, g->closest_peers[index].real_pk, crypto_box_PUBLICKEYBYTES);\n        memcpy(old_temp_pk, g->closest_peers[index].temp_pk, crypto_box_PUBLICKEYBYTES);\n        old = 1;\n    }\n\n    g->closest_peers[index].entry = 1;\n    memcpy(g->closest_peers[index].real_pk, real_pk, crypto_box_PUBLICKEYBYTES);\n    memcpy(g->closest_peers[index].temp_pk, temp_pk, crypto_box_PUBLICKEYBYTES);\n\n    if (old) {\n        add_to_closest(g_c, groupnumber, old_real_pk, old_temp_pk);\n    }\n\n    if (!g->changed)\n        g->changed = GROUPCHAT_CLOSEST_ADDED;\n\n    return 0;\n}\n\nstatic unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk)\n{\n    unsigned int i;\n\n    for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {\n        if (!g->closest_peers[i].entry)\n            continue;\n\n        if (public_key_cmp(g->closest_peers[i].real_pk, real_pk) == 0)\n            return 1;\n\n    }\n\n    return 0;\n}\n\nstatic int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier);\n\nstatic int connect_to_closest(Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if (!g->changed)\n        return 0;\n\n    unsigned int i;\n\n    if (g->changed == GROUPCHAT_CLOSEST_REMOVED) {\n        for (i = 0; i < g->numpeers; ++i) {\n            add_to_closest(g_c, groupnumber, g->group[i].real_pk, g->group[i].temp_pk);\n        }\n    }\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_NONE)\n            continue;\n\n        if (!g->close[i].closest)\n            continue;\n\n        uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n        uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];\n        get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number);\n\n        if (!pk_in_closest_peers(g, real_pk)) {\n            g->close[i].type = GROUPCHAT_CLOSE_NONE;\n            kill_friend_connection(g_c->fr_c, g->close[i].number);\n        }\n    }\n\n    for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) {\n        if (!g->closest_peers[i].entry)\n            continue;\n\n        int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->closest_peers[i].real_pk);\n\n        uint8_t lock = 1;\n\n        if (friendcon_id == -1) {\n            friendcon_id = new_friend_connection(g_c->fr_c, g->closest_peers[i].real_pk);\n            lock = 0;\n\n            if (friendcon_id == -1) {\n                continue;\n            }\n\n            set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk);\n        }\n\n        add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1, lock);\n\n        if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) {\n            send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier);\n        }\n    }\n\n    g->changed = GROUPCHAT_CLOSEST_NONE;\n\n    return 0;\n}\n\n/*\n * Add a peer to the group chat.\n *\n * return peer_index if success or peer already in chat.\n * return -1 if error.\n */\nstatic int addpeer(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk,\n                   uint16_t peer_number)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    //TODO\n    int peer_index = peer_in_chat(g, real_pk);\n\n    if (peer_index != -1) {\n        id_copy(g->group[peer_index].temp_pk, temp_pk);\n\n        if (g->group[peer_index].peer_number != peer_number)\n            return -1;\n\n        return peer_index;\n    }\n\n    peer_index = get_peer_index(g, peer_number);\n\n    if (peer_index != -1)\n        return -1;\n\n    Group_Peer *temp;\n    temp = realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1));\n\n    if (temp == NULL)\n        return -1;\n\n    memset(&(temp[g->numpeers]), 0, sizeof(Group_Peer));\n    g->group = temp;\n\n    id_copy(g->group[g->numpeers].real_pk, real_pk);\n    id_copy(g->group[g->numpeers].temp_pk, temp_pk);\n    g->group[g->numpeers].peer_number = peer_number;\n\n    g->group[g->numpeers].last_recv = unix_time();\n    ++g->numpeers;\n\n    add_to_closest(g_c, groupnumber, real_pk, temp_pk);\n\n    if (g_c->peer_namelistchange)\n        g_c->peer_namelistchange(g_c->m, groupnumber, g->numpeers - 1, CHAT_CHANGE_PEER_ADD,\n                                 g_c->group_namelistchange_userdata);\n\n    if (g->peer_on_join)\n        g->peer_on_join(g->object, groupnumber, g->numpeers - 1);\n\n    return (g->numpeers - 1);\n}\n\nstatic int remove_close_conn(Group_Chats *g_c, int groupnumber, int friendcon_id)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint32_t i;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_NONE)\n            continue;\n\n        if (g->close[i].number == (unsigned int)friendcon_id) {\n            g->close[i].type = GROUPCHAT_CLOSE_NONE;\n            kill_friend_connection(g_c->fr_c, friendcon_id);\n            return 0;\n        }\n    }\n\n    return -1;\n}\n\n\n/*\n * Delete a peer from the group chat.\n *\n * return 0 if success\n * return -1 if error.\n */\nstatic int delpeer(Group_Chats *g_c, int groupnumber, int peer_index)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint32_t i;\n\n    for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { /* If peer is in closest_peers list, remove it. */\n        if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) {\n            g->closest_peers[i].entry = 0;\n            g->changed = GROUPCHAT_CLOSEST_REMOVED;\n            break;\n        }\n    }\n\n    int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk);\n\n    if (friendcon_id != -1) {\n        remove_close_conn(g_c, groupnumber, friendcon_id);\n    }\n\n    Group_Peer *temp;\n    --g->numpeers;\n\n    void *peer_object = g->group[peer_index].object;\n\n    if (g->numpeers == 0) {\n        free(g->group);\n        g->group = NULL;\n    } else {\n        if (g->numpeers != (uint32_t)peer_index)\n            memcpy(&g->group[peer_index], &g->group[g->numpeers], sizeof(Group_Peer));\n\n        temp = realloc(g->group, sizeof(Group_Peer) * (g->numpeers));\n\n        if (temp == NULL)\n            return -1;\n\n        g->group = temp;\n    }\n\n    if (g_c->peer_namelistchange)\n        g_c->peer_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_DEL, g_c->group_namelistchange_userdata);\n\n    if (g->peer_on_leave)\n        g->peer_on_leave(g->object, groupnumber, peer_index, peer_object);\n\n    return 0;\n}\n\nstatic int setnick(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *nick, uint16_t nick_len)\n{\n    if (nick_len > MAX_NAME_LENGTH)\n        return -1;\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    /* same name as already stored? */\n    if (g->group[peer_index].nick_len == nick_len)\n        if (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len))\n            return 0;\n\n    if (nick_len)\n        memcpy(g->group[peer_index].nick, nick, nick_len);\n\n    g->group[peer_index].nick_len = nick_len;\n\n    if (g_c->peer_namelistchange)\n        g_c->peer_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_NAME, g_c->group_namelistchange_userdata);\n\n    return 0;\n}\n\nstatic int settitle(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *title, uint8_t title_len)\n{\n    if (title_len > MAX_NAME_LENGTH || title_len == 0)\n        return -1;\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    /* same as already set? */\n    if (g->title_len == title_len && !memcmp(g->title, title, title_len))\n        return 0;\n\n    memcpy(g->title, title, title_len);\n    g->title_len = title_len;\n\n    if (g_c->title_callback)\n        g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, g_c->title_callback_userdata);\n\n    return 0;\n}\n\nstatic void set_conns_type_close(Group_Chats *g_c, int groupnumber, int friendcon_id, uint8_t type)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return;\n\n    uint32_t i;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_NONE)\n            continue;\n\n        if (g->close[i].number != (unsigned int)friendcon_id)\n            continue;\n\n        if (type == GROUPCHAT_CLOSE_ONLINE) {\n            send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier);\n        } else {\n            g->close[i].type = type;\n        }\n    }\n}\n/* Set the type for all close connections with friendcon_id */\nstatic void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type)\n{\n    uint32_t i;\n\n    for (i = 0; i < g_c->num_chats; ++i) {\n        set_conns_type_close(g_c, i, friendcon_id, type);\n    }\n}\n\nstatic int handle_status(void *object, int friendcon_id, uint8_t status)\n{\n    Group_Chats *g_c = object;\n\n    if (status) { /* Went online */\n        set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE);\n    } else { /* Went offline */\n        set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION);\n        //TODO remove timedout connections?\n    }\n\n    return 0;\n}\n\nstatic int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length);\nstatic int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length);\n\n/* Add friend to group chat.\n *\n * return close index on success\n * return -1 on failure.\n */\nstatic int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint16_t i, ind = MAX_GROUP_CONNECTIONS;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_NONE) {\n            ind = i;\n            continue;\n        }\n\n        if (g->close[i].number == (uint32_t)friendcon_id) {\n            g->close[i].closest = closest;\n            return i; /* Already in list. */\n        }\n    }\n\n    if (ind == MAX_GROUP_CONNECTIONS)\n        return -1;\n\n    if (lock)\n        friend_connection_lock(g_c->fr_c, friendcon_id);\n\n    g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION;\n    g->close[ind].number = friendcon_id;\n    g->close[ind].closest = closest;\n    //TODO\n    friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &handle_status, &handle_packet,\n                                &handle_lossy, g_c, friendcon_id);\n\n    return ind;\n}\n\n/* Creates a new groupchat and puts it in the chats array.\n *\n * type is one of GROUPCHAT_TYPE_*\n *\n * return group number on success.\n * return -1 on failure.\n */\nint add_groupchat(Group_Chats *g_c, uint8_t type)\n{\n    int groupnumber = create_group_chat(g_c);\n\n    if (groupnumber == -1)\n        return -1;\n\n    Group_c *g = &g_c->chats[groupnumber];\n\n    g->status = GROUPCHAT_STATUS_CONNECTED;\n    g->number_joined = -1;\n    new_symmetric_key(g->identifier + 1);\n    g->identifier[0] = type;\n    g->peer_number = 0; /* Founder is peer 0. */\n    memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES);\n    int peer_index = addpeer(g_c, groupnumber, g->real_pk, g_c->m->dht->self_public_key, 0);\n\n    if (peer_index == -1) {\n        return -1;\n    }\n\n    setnick(g_c, groupnumber, peer_index, g_c->m->name, g_c->m->name_length);\n\n    return groupnumber;\n}\n\nstatic int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num);\n/* Delete a groupchat from the chats array.\n *\n * return 0 on success.\n * return -1 if failure.\n */\nint del_groupchat(Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    group_kill_peer_send(g_c, groupnumber, g->peer_number);\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_NONE)\n            continue;\n\n        g->close[i].type = GROUPCHAT_CLOSE_NONE;\n        kill_friend_connection(g_c->fr_c, g->close[i].number);\n    }\n\n    for (i = 0; i < g->numpeers; ++i) {\n        if (g->peer_on_leave)\n            g->peer_on_leave(g->object, groupnumber, i, g->group[i].object);\n    }\n\n    free(g->group);\n\n    if (g->group_on_delete)\n        g->group_on_delete(g->object, groupnumber);\n\n    return wipe_group_chat(g_c, groupnumber);\n}\n\n/* Copy the public key of peernumber who is in groupnumber to pk.\n * pk must be crypto_box_PUBLICKEYBYTES long.\n *\n * returns 0 on success\n * returns -1 on failure\n */\nint group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if ((uint32_t)peernumber >= g->numpeers)\n        return -1;\n\n    memcpy(pk, g->group[peernumber].real_pk, crypto_box_PUBLICKEYBYTES);\n    return 0;\n}\n\n/* Copy the name of peernumber who is in groupnumber to name.\n * name must be at least MAX_NAME_LENGTH long.\n *\n * return length of name if success\n * return -1 if failure\n */\nint group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if ((uint32_t)peernumber >= g->numpeers)\n        return -1;\n\n    if (g->group[peernumber].nick_len == 0) {\n        memcpy(name, \"Tox User\", 8);\n        return 8;\n    }\n\n    memcpy(name, g->group[peernumber].nick, g->group[peernumber].nick_len);\n    return g->group[peernumber].nick_len;\n}\n\n/* List all the peers in the group chat.\n *\n * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array.\n *\n * Copies the lengths of the names to lengths[length]\n *\n * returns the number of peers on success.\n *\n * return -1 on failure.\n */\nint group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[],\n                uint16_t length)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    unsigned int i;\n\n    for (i = 0; i < g->numpeers && i < length; ++i) {\n        lengths[i] = group_peername(g_c, groupnumber, i, names[i]);\n    }\n\n    return i;\n}\n\n/* Return the number of peers in the group chat on success.\n * return -1 on failure\n */\nint group_number_peers(const Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    return g->numpeers;\n}\n\n/* return 1 if the peernumber corresponds to ours.\n * return 0 on failure.\n */\nunsigned int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return 0;\n\n    if (g->status != GROUPCHAT_STATUS_CONNECTED)\n        return 0;\n\n    if ((uint32_t)peernumber >= g->numpeers)\n        return 0;\n\n    return g->peer_number == g->group[peernumber].peer_number;\n}\n\n/* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is.\n *\n * return -1 on failure.\n * return type on success.\n */\nint group_get_type(const Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    return g->identifier[0];\n}\n\n/* Send a group packet to friendcon_id.\n *\n *  return 1 on success\n *  return 0 on failure\n */\nstatic unsigned int send_packet_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id,\n        uint16_t group_num, const uint8_t *data, uint16_t length)\n{\n    if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE)\n        return 0;\n\n    group_num = htons(group_num);\n    uint8_t packet[1 + sizeof(uint16_t) + length];\n    packet[0] = packet_id;\n    memcpy(packet + 1, &group_num, sizeof(uint16_t));\n    memcpy(packet + 1 + sizeof(uint16_t), data, length);\n    return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet,\n                             sizeof(packet), 0) != -1;\n}\n\n/* Send a group lossy packet to friendcon_id.\n *\n *  return 1 on success\n *  return 0 on failure\n */\nstatic unsigned int send_lossy_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id,\n        uint16_t group_num, const uint8_t *data, uint16_t length)\n{\n    if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE)\n        return 0;\n\n    group_num = htons(group_num);\n    uint8_t packet[1 + sizeof(uint16_t) + length];\n    packet[0] = packet_id;\n    memcpy(packet + 1, &group_num, sizeof(uint16_t));\n    memcpy(packet + 1 + sizeof(uint16_t), data, length);\n    return send_lossy_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet,\n                                  sizeof(packet)) != -1;\n}\n\n#define INVITE_PACKET_SIZE (1 + sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH)\n#define INVITE_ID 0\n\n#define INVITE_RESPONSE_PACKET_SIZE (1 + sizeof(uint16_t) * 2 + GROUP_IDENTIFIER_LENGTH)\n#define INVITE_RESPONSE_ID 1\n\n/* invite friendnumber to groupnumber\n * return 0 on success\n * return -1 on failure\n */\nint invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint8_t invite[INVITE_PACKET_SIZE];\n    invite[0] = INVITE_ID;\n    uint16_t groupchat_num = htons((uint16_t)groupnumber);\n    memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num));\n    memcpy(invite + 1 + sizeof(groupchat_num), g->identifier, GROUP_IDENTIFIER_LENGTH);\n\n    if (send_group_invite_packet(g_c->m, friendnumber, invite, sizeof(invite))) {\n        return 0;\n    } else {\n        wipe_group_chat(g_c, groupnumber);\n        return -1;\n    }\n}\n\nstatic unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num);\n\n/* Join a group (you need to have been invited first.)\n *\n * expected_type is the groupchat type we expect the chat we are joining is.\n *\n * returns group number on success\n * returns -1 on failure.\n */\nint join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length)\n{\n    if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH)\n        return -1;\n\n    if (data[sizeof(uint16_t)] != expected_type)\n        return -1;\n\n    int friendcon_id = getfriendcon_id(g_c->m, friendnumber);\n\n    if (friendcon_id == -1)\n        return -1;\n\n    if (get_group_num(g_c, data + sizeof(uint16_t)) != -1)\n        return -1;\n\n    int groupnumber = create_group_chat(g_c);\n\n    if (groupnumber == -1)\n        return -1;\n\n    Group_c *g = &g_c->chats[groupnumber];\n\n    uint16_t group_num = htons(groupnumber);\n    g->status = GROUPCHAT_STATUS_VALID;\n    g->number_joined = -1;\n    memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES);\n\n    uint8_t response[INVITE_RESPONSE_PACKET_SIZE];\n    response[0] = INVITE_RESPONSE_ID;\n    memcpy(response + 1, &group_num, sizeof(uint16_t));\n    memcpy(response + 1 + sizeof(uint16_t), data, sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH);\n\n    if (send_group_invite_packet(g_c->m, friendnumber, response, sizeof(response))) {\n        uint16_t other_groupnum;\n        memcpy(&other_groupnum, data, sizeof(other_groupnum));\n        other_groupnum = ntohs(other_groupnum);\n        memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH);\n        int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0, 1);\n\n        if (close_index != -1) {\n            g->close[close_index].group_number = other_groupnum;\n            g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE;\n            g->number_joined = friendcon_id;\n        }\n\n        send_peer_query(g_c, friendcon_id, other_groupnum);\n        return groupnumber;\n    } else {\n        g->status = GROUPCHAT_STATUS_NONE;\n        return -1;\n    }\n}\n\n/* Set the callback for group invites.\n *\n *  Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata)\n *\n *  data of length is what needs to be passed to join_groupchat().\n */\nvoid g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *,\n                             uint16_t, void *), void *userdata)\n{\n    g_c->invite_callback = function;\n    g_c->invite_callback_userdata = userdata;\n}\n\n/* Set the callback for group messages.\n *\n *  Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)\n */\nvoid g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t,\n                              void *), void *userdata)\n{\n    g_c->message_callback = function;\n    g_c->message_callback_userdata = userdata;\n}\n\n/* Set the callback for group actions.\n *\n *  Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)\n */\nvoid g_callback_group_action(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t,\n                             void *), void *userdata)\n{\n    g_c->action_callback = function;\n    g_c->action_callback_userdata = userdata;\n}\n\n/* Set handlers for custom lossy packets.\n *\n * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed.\n *\n * 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)\n */\nvoid group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *,\n                                        const uint8_t *, uint16_t))\n{\n    g_c->lossy_packethandlers[byte].function = function;\n}\n\n/* Set callback function for peer name list changes.\n *\n * It gets called every time the name list changes(new peer/name, deleted peer)\n *  Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata)\n */\nvoid g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *),\n                                     void *userdata)\n{\n    g_c->peer_namelistchange = function;\n    g_c->group_namelistchange_userdata = userdata;\n}\n\n/* Set callback function for title changes.\n *\n * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata)\n * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group)\n */\nvoid g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint8_t,\n                            void *), void *userdata)\n{\n    g_c->title_callback = function;\n    g_c->title_callback_userdata = userdata;\n}\n\n/* Set a function to be called when a new peer joins a group chat.\n *\n * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber)\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int))\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    g->peer_on_join = function;\n    return 0;\n}\n\n/* Set a function to be called when a peer leaves a group chat.\n *\n * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object))\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *))\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    g->peer_on_leave = function;\n    return 0;\n}\n\n/* Set a function to be called when the group chat is deleted.\n *\n * Function(void *group object (set with group_set_object), int groupnumber)\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int))\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    g->group_on_delete = function;\n    return 0;\n}\n\nstatic unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data,\n                                       uint16_t len);\n\n#define GROUP_MESSAGE_PING_ID 0\nint group_ping_send(const Group_Chats *g_c, int groupnumber)\n{\n    if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_PING_ID, 0, 0)) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n#define GROUP_MESSAGE_NEW_PEER_ID 16\n#define GROUP_MESSAGE_NEW_PEER_LENGTH (sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2)\n/* send a new_peer message\n * return 0 on success\n * return -1 on failure\n */\nint group_new_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num, const uint8_t *real_pk,\n                        uint8_t *temp_pk)\n{\n    uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH];\n\n    peer_num = htons(peer_num);\n    memcpy(packet, &peer_num, sizeof(uint16_t));\n    memcpy(packet + sizeof(uint16_t), real_pk, crypto_box_PUBLICKEYBYTES);\n    memcpy(packet + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES, temp_pk, crypto_box_PUBLICKEYBYTES);\n\n    if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet))) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n#define GROUP_MESSAGE_KILL_PEER_ID 17\n#define GROUP_MESSAGE_KILL_PEER_LENGTH (sizeof(uint16_t))\n\n/* send a kill_peer message\n * return 0 on success\n * return -1 on failure\n */\nstatic int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num)\n{\n    uint8_t packet[GROUP_MESSAGE_KILL_PEER_LENGTH];\n\n    peer_num = htons(peer_num);\n    memcpy(packet, &peer_num, sizeof(uint16_t));\n\n    if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_KILL_PEER_ID, packet, sizeof(packet))) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n#define GROUP_MESSAGE_NAME_ID 48\n\n/* send a name message\n * return 0 on success\n * return -1 on failure\n */\nstatic int group_name_send(const Group_Chats *g_c, int groupnumber, const uint8_t *nick, uint16_t nick_len)\n{\n    if (nick_len > MAX_NAME_LENGTH)\n        return -1;\n\n    if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NAME_ID, nick, nick_len)) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n#define GROUP_MESSAGE_TITLE_ID 49\n\n/* set the group's title, limited to MAX_NAME_LENGTH\n * return 0 on success\n * return -1 on failure\n */\nint group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len)\n{\n    if (title_len > MAX_NAME_LENGTH || title_len == 0)\n        return -1;\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    /* same as already set? */\n    if (g->title_len == title_len && !memcmp(g->title, title, title_len))\n        return 0;\n\n    memcpy(g->title, title, title_len);\n    g->title_len = title_len;\n\n    if (g->numpeers == 1)\n        return 0;\n\n    if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_TITLE_ID, title, title_len))\n        return 0;\n    else\n        return -1;\n}\n\n/* Get group title from groupnumber and put it in title.\n * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes.\n *\n *  return length of copied title if success.\n *  return -1 if failure.\n */\nint group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title, uint32_t max_length)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH)\n        return -1;\n\n    if (max_length > g->title_len)\n        max_length = g->title_len;\n\n    memcpy(title, g->title, max_length);\n    return max_length;\n}\n\nstatic void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length)\n{\n    Group_Chats *g_c = m->group_chat_object;\n\n    if (length <= 1)\n        return;\n\n    const uint8_t *invite_data = data + 1;\n    uint16_t invite_length = length - 1;\n\n    switch (data[0]) {\n        case INVITE_ID: {\n            if (length != INVITE_PACKET_SIZE)\n                return;\n\n            int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t));\n\n            if (groupnumber == -1) {\n                if (g_c->invite_callback)\n                    g_c->invite_callback(m, friendnumber, *(invite_data + sizeof(uint16_t)), invite_data, invite_length,\n                                         g_c->invite_callback_userdata);\n\n                return;\n            }\n\n            break;\n        }\n\n        case INVITE_RESPONSE_ID: {\n            if (length != INVITE_RESPONSE_PACKET_SIZE)\n                return;\n\n            uint16_t other_groupnum, groupnum;\n            memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t));\n            groupnum = ntohs(groupnum);\n\n            Group_c *g = get_group_c(g_c, groupnum);\n\n            if (!g)\n                return;\n\n            if (sodium_memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0)\n                return;\n\n            uint16_t peer_number = rand(); /* TODO: what if two people enter the group at the same time and\n  are given the same peer_number by different nodes? */\n\n            unsigned int tries = 0;\n\n            while (get_peer_index(g, peer_number) != -1) {\n                peer_number = rand();\n                ++tries;\n\n                if (tries > 32)\n                    return;\n            }\n\n            memcpy(&other_groupnum, data + 1, sizeof(uint16_t));\n            other_groupnum = ntohs(other_groupnum);\n\n            int friendcon_id = getfriendcon_id(m, friendnumber);\n            uint8_t real_pk[crypto_box_PUBLICKEYBYTES], temp_pk[crypto_box_PUBLICKEYBYTES];\n            get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id);\n\n            addpeer(g_c, groupnum, real_pk, temp_pk, peer_number);\n            int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0, 1);\n\n            if (close_index != -1) {\n                g->close[close_index].group_number = other_groupnum;\n                g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE;\n            }\n\n            group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk);\n            break;\n        }\n\n        default:\n            return;\n    }\n}\n\n/* Find index of friend in the close list;\n *\n * returns index on success\n * returns -1 on failure.\n */\nstatic int friend_in_close(Group_c *g, int friendcon_id)\n{\n    unsigned int i;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_NONE)\n            continue;\n\n        if (g->close[i].number != (uint32_t)friendcon_id)\n            continue;\n\n        return i;\n    }\n\n    return -1;\n}\n\n/* return number of connected close connections.\n */\nstatic unsigned int count_close_connected(Group_c *g)\n{\n    unsigned int i, count = 0;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) {\n            ++count;\n        }\n    }\n\n    return count;\n}\n\n#define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH)\n\nstatic int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier)\n{\n    uint8_t packet[1 + ONLINE_PACKET_DATA_SIZE];\n    group_num = htons(group_num);\n    packet[0] = PACKET_ID_ONLINE_PACKET;\n    memcpy(packet + 1, &group_num, sizeof(uint16_t));\n    memcpy(packet + 1 + sizeof(uint16_t), identifier, GROUP_IDENTIFIER_LENGTH);\n    return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet,\n                             sizeof(packet), 0) != -1;\n}\n\nstatic unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num);\n\nstatic int handle_packet_online(Group_Chats *g_c, int friendcon_id, uint8_t *data, uint16_t length)\n{\n    if (length != ONLINE_PACKET_DATA_SIZE)\n        return -1;\n\n    int groupnumber = get_group_num(g_c, data + sizeof(uint16_t));\n    uint16_t other_groupnum;\n    memcpy(&other_groupnum, data, sizeof(uint16_t));\n    other_groupnum = ntohs(other_groupnum);\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    int index = friend_in_close(g, friendcon_id);\n\n    if (index == -1)\n        return -1;\n\n    if (g->close[index].type == GROUPCHAT_CLOSE_ONLINE) {\n        return -1;\n    }\n\n    if (count_close_connected(g) == 0) {\n        send_peer_query(g_c, friendcon_id, other_groupnum);\n    }\n\n    g->close[index].group_number = other_groupnum;\n    g->close[index].type = GROUPCHAT_CLOSE_ONLINE;\n    send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier);\n\n    if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) {\n        int fr_close_index = friend_in_close(g, g->number_joined);\n\n        if (fr_close_index == -1)\n            return -1;\n\n        if (!g->close[fr_close_index].closest) {\n            g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE;\n            send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number);\n            kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number);\n            g->number_joined = -1;\n        }\n    }\n\n    return 0;\n}\n\n#define PEER_KILL_ID 1\n#define PEER_QUERY_ID 8\n#define PEER_RESPONSE_ID 9\n#define PEER_TITLE_ID 10\n// we could send title with invite, but then if it changes between sending and accepting inv, joinee won't see it\n\n/* return 1 on success.\n * return 0 on failure\n */\nstatic unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num)\n{\n    uint8_t packet[1];\n    packet[0] = PEER_KILL_ID;\n    return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, sizeof(packet));\n}\n\n\n/* return 1 on success.\n * return 0 on failure\n */\nstatic unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num)\n{\n    uint8_t packet[1];\n    packet[0] = PEER_QUERY_ID;\n    return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, sizeof(packet));\n}\n\n/* return number of peers sent on success.\n * return 0 on failure.\n */\nstatic unsigned int send_peers(Group_Chats *g_c, int groupnumber, int friendcon_id, uint16_t group_num)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint8_t packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))];\n    packet[0] = PEER_RESPONSE_ID;\n    uint8_t *p = packet + 1;\n\n    uint16_t sent = 0;\n    unsigned int i;\n\n    for (i = 0; i < g->numpeers; ++i) {\n        if ((p - packet) + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2 + 1 + g->group[i].nick_len > sizeof(packet)) {\n            if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, (p - packet))) {\n                sent = i;\n            } else {\n                return sent;\n            }\n\n            p = packet + 1;\n        }\n\n        uint16_t peer_num = htons(g->group[i].peer_number);\n        memcpy(p, &peer_num, sizeof(peer_num));\n        p += sizeof(peer_num);\n        memcpy(p, g->group[i].real_pk, crypto_box_PUBLICKEYBYTES);\n        p += crypto_box_PUBLICKEYBYTES;\n        memcpy(p, g->group[i].temp_pk, crypto_box_PUBLICKEYBYTES);\n        p += crypto_box_PUBLICKEYBYTES;\n        *p = g->group[i].nick_len;\n        p += 1;\n        memcpy(p, g->group[i].nick, g->group[i].nick_len);\n        p += g->group[i].nick_len;\n    }\n\n    if (sent != i) {\n        if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, packet, (p - packet))) {\n            sent = i;\n        }\n    }\n\n    if (g->title_len) {\n        uint8_t Packet[1 + g->title_len];\n        Packet[0] = PEER_TITLE_ID;\n        memcpy(Packet + 1, g->title, g->title_len);\n        send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_GROUPCHAT, group_num, Packet, sizeof(Packet));\n    }\n\n    return sent;\n}\n\nstatic int handle_send_peers(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length)\n{\n    if (length == 0)\n        return -1;\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    const uint8_t *d = data;\n\n    while ((unsigned int)(length - (d - data)) >= sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES * 2 + 1) {\n        uint16_t peer_num;\n        memcpy(&peer_num, d, sizeof(peer_num));\n        peer_num = ntohs(peer_num);\n        d += sizeof(uint16_t);\n        int peer_index = addpeer(g_c, groupnumber, d, d + crypto_box_PUBLICKEYBYTES, peer_num);\n\n        if (peer_index == -1)\n            return -1;\n\n        if (g->status == GROUPCHAT_STATUS_VALID\n                && public_key_cmp(d, g_c->m->net_crypto->self_public_key) == 0) {\n            g->peer_number = peer_num;\n            g->status = GROUPCHAT_STATUS_CONNECTED;\n            group_name_send(g_c, groupnumber, g_c->m->name, g_c->m->name_length);\n        }\n\n        d += crypto_box_PUBLICKEYBYTES * 2;\n        uint8_t name_length = *d;\n        d += 1;\n\n        if (name_length > (length - (d - data)) || name_length > MAX_NAME_LENGTH)\n            return -1;\n\n        setnick(g_c, groupnumber, peer_index, d, name_length);\n        d += name_length;\n    }\n\n    return 0;\n}\n\nstatic void handle_direct_packet(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,\n                                 int close_index)\n{\n    if (length == 0)\n        return;\n\n    switch (data[0]) {\n        case PEER_KILL_ID: {\n            Group_c *g = get_group_c(g_c, groupnumber);\n\n            if (!g)\n                return;\n\n            if (!g->close[close_index].closest) {\n                g->close[close_index].type = GROUPCHAT_CLOSE_NONE;\n                kill_friend_connection(g_c->fr_c, g->close[close_index].number);\n            }\n        }\n\n        break;\n\n        case PEER_QUERY_ID: {\n            Group_c *g = get_group_c(g_c, groupnumber);\n\n            if (!g)\n                return;\n\n            send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number);\n        }\n\n        break;\n\n        case PEER_RESPONSE_ID: {\n            handle_send_peers(g_c, groupnumber, data + 1, length - 1);\n        }\n\n        break;\n\n        case PEER_TITLE_ID: {\n            settitle(g_c, groupnumber, -1, data + 1, length - 1);\n        }\n\n        break;\n    }\n}\n\n#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1)\n\n/* Send message to all close except receiver (if receiver isn't -1)\n * NOTE: this function appends the group chat number to the data passed to it.\n *\n * return number of messages sent.\n */\nstatic unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data,\n        uint16_t length, int receiver)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return 0;\n\n    uint16_t i, sent = 0;\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE)\n            continue;\n\n        if ((int)i == receiver)\n            continue;\n\n        if (send_packet_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_MESSAGE_GROUPCHAT, g->close[i].group_number, data,\n                                   length))\n            ++sent;\n    }\n\n    return sent;\n}\n\n/* Send lossy message to all close except receiver (if receiver isn't -1)\n * NOTE: this function appends the group chat number to the data passed to it.\n *\n * return number of messages sent.\n */\nstatic unsigned int send_lossy_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,\n        int receiver)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return 0;\n\n    unsigned int i, sent = 0, num_connected_closest = 0, connected_closest[DESIRED_CLOSE_CONNECTIONS];\n\n    for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) {\n        if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE)\n            continue;\n\n        if ((int)i == receiver)\n            continue;\n\n        if (g->close[i].closest) {\n            connected_closest[num_connected_closest] = i;\n            ++num_connected_closest;\n            continue;\n        }\n\n        if (send_lossy_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_LOSSY_GROUPCHAT, g->close[i].group_number, data,\n                                  length))\n            ++sent;\n    }\n\n    if (!num_connected_closest) {\n        return sent;\n    }\n\n    unsigned int to_send = 0;\n    uint64_t comp_val_old = ~0;\n\n    for (i = 0; i < num_connected_closest; ++i) {\n        uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n        uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];\n        get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number);\n        uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk);\n\n        if (comp_val < comp_val_old) {\n            to_send = connected_closest[i];\n            comp_val_old = comp_val;\n        }\n    }\n\n    if (send_lossy_group_peer(g_c->fr_c, g->close[to_send].number, PACKET_ID_LOSSY_GROUPCHAT,\n                              g->close[to_send].group_number, data, length)) {\n        ++sent;\n    }\n\n    unsigned int to_send_other = 0;\n    comp_val_old = ~0;\n\n    for (i = 0; i < num_connected_closest; ++i) {\n        uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n        uint8_t dht_temp_pk[crypto_box_PUBLICKEYBYTES];\n        get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number);\n        uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk);\n\n        if (comp_val < comp_val_old) {\n            to_send_other = connected_closest[i];\n            comp_val_old = comp_val;\n        }\n    }\n\n    if (to_send_other == to_send) {\n        return sent;\n    }\n\n    if (send_lossy_group_peer(g_c->fr_c, g->close[to_send_other].number, PACKET_ID_LOSSY_GROUPCHAT,\n                              g->close[to_send_other].group_number, data, length)) {\n        ++sent;\n    }\n\n    return sent;\n}\n\n#define MAX_GROUP_MESSAGE_DATA_LEN (MAX_CRYPTO_DATA_SIZE - (1 + MIN_MESSAGE_PACKET_LEN))\n\n/* Send data of len with message_id to groupnumber.\n *\n * return number of peers it was sent to on success.\n * return 0 on failure.\n */\nstatic unsigned int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data,\n                                       uint16_t len)\n{\n    if (len > MAX_GROUP_MESSAGE_DATA_LEN)\n        return 0;\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return 0;\n\n    if (g->status != GROUPCHAT_STATUS_CONNECTED)\n        return 0;\n\n    uint8_t packet[sizeof(uint16_t) + sizeof(uint32_t) + 1 + len];\n    uint16_t peer_num = htons(g->peer_number);\n    memcpy(packet, &peer_num, sizeof(peer_num));\n\n    ++g->message_number;\n\n    if (!g->message_number)\n        ++g->message_number;\n\n    uint32_t message_num = htonl(g->message_number);\n    memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num));\n\n    packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id;\n\n    if (len)\n        memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len);\n\n    return send_message_all_close(g_c, groupnumber, packet, sizeof(packet), -1);\n}\n\n/* send a group message\n * return 0 on success\n * return -1 on failure\n */\nint group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length)\n{\n    if (send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length)) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n/* send a group action\n * return 0 on success\n * return -1 on failure\n */\nint group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length)\n{\n    if (send_message_group(g_c, groupnumber, PACKET_ID_ACTION, action, length)) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n/* High level function to send custom lossy packets.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length)\n{\n    //TODO: length check here?\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint8_t packet[sizeof(uint16_t) * 2 + length];\n    uint16_t peer_number = htons(g->peer_number);\n    memcpy(packet, &peer_number, sizeof(uint16_t));\n    uint16_t message_num = htons(g->lossy_message_number);\n    memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t));\n    memcpy(packet + sizeof(uint16_t) * 2, data, length);\n\n    if (send_lossy_all_close(g_c, groupnumber, packet, sizeof(packet), -1) == 0) {\n        return -1;\n    }\n\n    ++g->lossy_message_number;\n    return 0;\n}\n\nstatic void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length,\n                                        int close_index)\n{\n    if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1)\n        return;\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return;\n\n    uint16_t peer_number;\n    memcpy(&peer_number, data, sizeof(uint16_t));\n    peer_number = ntohs(peer_number);\n\n    int index = get_peer_index(g, peer_number);\n\n    if (index == -1) {\n        /* We don't know the peer this packet came from so we query the list of peers from that peer.\n          (They would not have relayed it if they didn't know the peer.) */\n        send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number);\n        return;\n    }\n\n    uint32_t message_number;\n    memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number));\n    message_number = ntohl(message_number);\n\n    if (g->group[index].last_message_number == 0) {\n        g->group[index].last_message_number = message_number;\n    } else if (message_number - g->group[index].last_message_number > 64 ||\n               message_number == g->group[index].last_message_number) {\n        return;\n    }\n\n    g->group[index].last_message_number = message_number;\n\n    uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)];\n    const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1;\n    uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1);\n\n    switch (message_id) {\n        case GROUP_MESSAGE_PING_ID: {\n            if (msg_data_len != 0)\n                return;\n\n            g->group[index].last_recv = unix_time();\n        }\n        break;\n\n        case GROUP_MESSAGE_NEW_PEER_ID: {\n            if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH)\n                return;\n\n            uint16_t new_peer_number;\n            memcpy(&new_peer_number, msg_data, sizeof(uint16_t));\n            new_peer_number = ntohs(new_peer_number);\n            addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + crypto_box_PUBLICKEYBYTES,\n                    new_peer_number);\n        }\n        break;\n\n        case GROUP_MESSAGE_KILL_PEER_ID: {\n            if (msg_data_len != GROUP_MESSAGE_KILL_PEER_LENGTH)\n                return;\n\n            uint16_t kill_peer_number;\n            memcpy(&kill_peer_number, msg_data, sizeof(uint16_t));\n            kill_peer_number = ntohs(kill_peer_number);\n\n            if (peer_number == kill_peer_number) {\n                delpeer(g_c, groupnumber, index);\n            } else {\n                return;\n                //TODO\n            }\n        }\n        break;\n\n        case GROUP_MESSAGE_NAME_ID: {\n            if (setnick(g_c, groupnumber, index, msg_data, msg_data_len) == -1)\n                return;\n        }\n        break;\n\n        case GROUP_MESSAGE_TITLE_ID: {\n            if (settitle(g_c, groupnumber, index, msg_data, msg_data_len) == -1)\n                return;\n        }\n        break;\n\n        case PACKET_ID_MESSAGE: {\n            if (msg_data_len == 0)\n                return;\n\n            uint8_t newmsg[msg_data_len + 1];\n            memcpy(newmsg, msg_data, msg_data_len);\n            newmsg[msg_data_len] = 0;\n\n            //TODO\n            if (g_c->message_callback)\n                g_c->message_callback(g_c->m, groupnumber, index, newmsg, msg_data_len, g_c->message_callback_userdata);\n\n            break;\n        }\n\n        case PACKET_ID_ACTION: {\n            if (msg_data_len == 0)\n                return;\n\n            uint8_t newmsg[msg_data_len + 1];\n            memcpy(newmsg, msg_data, msg_data_len);\n            newmsg[msg_data_len] = 0;\n\n            //TODO\n            if (g_c->action_callback)\n                g_c->action_callback(g_c->m, groupnumber, index, newmsg, msg_data_len, g_c->action_callback_userdata);\n\n            break;\n        }\n\n        default:\n            return;\n    }\n\n    send_message_all_close(g_c, groupnumber, data, length, -1/*TODO close_index*/);\n}\n\nstatic int handle_packet(void *object, int friendcon_id, uint8_t *data, uint16_t length)\n{\n    Group_Chats *g_c = object;\n\n    if (length < 1 + sizeof(uint16_t) + 1)\n        return -1;\n\n    if (data[0] == PACKET_ID_ONLINE_PACKET) {\n        return handle_packet_online(g_c, friendcon_id, data + 1, length - 1);\n    }\n\n    if (data[0] != PACKET_ID_DIRECT_GROUPCHAT && data[0] != PACKET_ID_MESSAGE_GROUPCHAT)\n        return -1;\n\n    uint16_t groupnumber;\n    memcpy(&groupnumber, data + 1, sizeof(uint16_t));\n    groupnumber = ntohs(groupnumber);\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    int index = friend_in_close(g, friendcon_id);\n\n    if (index == -1)\n        return -1;\n\n    switch (data[0]) {\n        case PACKET_ID_DIRECT_GROUPCHAT: {\n            handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);\n            break;\n        }\n\n        case PACKET_ID_MESSAGE_GROUPCHAT: {\n            handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);\n            break;\n        }\n\n        default: {\n            return 0;\n        }\n    }\n\n    return 0;\n}\n\n/* Did we already receive the lossy packet or not.\n *\n * return -1 on failure.\n * return 0 if packet was not received.\n * return 1 if packet was received.\n *\n * TODO: test this\n */\nstatic unsigned int lossy_packet_not_received(Group_c *g, int peer_index, uint16_t message_number)\n{\n    if (peer_index == -1)\n        return -1;\n\n    if (g->group[peer_index].bottom_lossy_number == g->group[peer_index].top_lossy_number) {\n        g->group[peer_index].top_lossy_number = message_number;\n        g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1;\n        g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1;\n        return 0;\n    }\n\n    if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) < MAX_LOSSY_COUNT) {\n        if (g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT]) {\n            return 1;\n        }\n\n        g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1;\n        return 0;\n    }\n\n    if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) > (1 << 15))\n        return -1;\n\n    uint16_t top_distance = message_number - g->group[peer_index].top_lossy_number;\n\n    if (top_distance >= MAX_LOSSY_COUNT) {\n        sodium_memzero(g->group[peer_index].recv_lossy, sizeof(g->group[peer_index].recv_lossy));\n        g->group[peer_index].top_lossy_number = message_number;\n        g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1;\n        g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1;\n        return 0;\n    }\n\n    if (top_distance < MAX_LOSSY_COUNT) {\n        unsigned int i;\n\n        for (i = g->group[peer_index].bottom_lossy_number; i != (g->group[peer_index].bottom_lossy_number + top_distance);\n                ++i) {\n            g->group[peer_index].recv_lossy[i % MAX_LOSSY_COUNT] = 0;\n        }\n\n        g->group[peer_index].top_lossy_number = message_number;\n        g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1;\n        g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1;\n        return 0;\n    }\n\n    return -1;\n}\n\nstatic int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length)\n{\n    Group_Chats *g_c = object;\n\n    if (length < 1 + sizeof(uint16_t) * 3 + 1)\n        return -1;\n\n    if (data[0] != PACKET_ID_LOSSY_GROUPCHAT)\n        return -1;\n\n    uint16_t groupnumber, peer_number, message_number;\n    memcpy(&groupnumber, data + 1, sizeof(uint16_t));\n    memcpy(&peer_number, data + 1 + sizeof(uint16_t), sizeof(uint16_t));\n    memcpy(&message_number, data + 1 + sizeof(uint16_t) * 2, sizeof(uint16_t));\n    groupnumber = ntohs(groupnumber);\n    peer_number = ntohs(peer_number);\n    message_number = ntohs(message_number);\n\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    int index = friend_in_close(g, friendcon_id);\n\n    if (index == -1)\n        return -1;\n\n    if (peer_number == g->peer_number)\n        return -1;\n\n    int peer_index = get_peer_index(g, peer_number);\n\n    if (peer_index == -1)\n        return -1;\n\n    if (lossy_packet_not_received(g, peer_index, message_number))\n        return -1;\n\n    const uint8_t *lossy_data = data + 1 + sizeof(uint16_t) * 3;\n    uint16_t lossy_length = length - (1 + sizeof(uint16_t) * 3);\n    uint8_t message_id = lossy_data[0];\n    ++lossy_data;\n    --lossy_length;\n\n    if (g_c->lossy_packethandlers[message_id].function) {\n        if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object,\n                lossy_data, lossy_length) == -1) {\n            return -1;\n        }\n    } else {\n        return -1;\n    }\n\n    send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index);\n    return 0;\n}\n\n/* Set the object that is tied to the group chat.\n *\n * return 0 on success.\n * return -1 on failure\n */\nint group_set_object(const Group_Chats *g_c, int groupnumber, void *object)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    g->object = object;\n    return 0;\n}\n\n/* Set the object that is tied to the group peer.\n *\n * return 0 on success.\n * return -1 on failure\n */\nint group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if ((uint32_t)peernumber >= g->numpeers)\n        return -1;\n\n    g->group[peernumber].object = object;\n    return 0;\n}\n\n/* Return the object tide to the group chat previously set by group_set_object.\n *\n * return NULL on failure.\n * return object on success.\n */\nvoid *group_get_object(const Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return NULL;\n\n    return g->object;\n}\n\n/* Return the object tide to the group chat peer previously set by group_peer_set_object.\n *\n * return NULL on failure.\n * return object on success.\n */\nvoid *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return NULL;\n\n    if ((uint32_t)peernumber >= g->numpeers)\n        return NULL;\n\n    return g->group[peernumber].object;\n}\n\n/* Interval in seconds to send ping messages */\n#define GROUP_PING_INTERVAL 20\n\nstatic int ping_groupchat(Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    if (is_timeout(g->last_sent_ping, GROUP_PING_INTERVAL)) {\n        if (group_ping_send(g_c, groupnumber) != -1) /* Ping */\n            g->last_sent_ping = unix_time();\n    }\n\n    return 0;\n}\n\nstatic int groupchat_clear_timedout(Group_Chats *g_c, int groupnumber)\n{\n    Group_c *g = get_group_c(g_c, groupnumber);\n\n    if (!g)\n        return -1;\n\n    uint32_t i;\n\n    for (i = 0; i < g->numpeers; ++i) {\n        if (g->peer_number != g->group[i].peer_number && is_timeout(g->group[i].last_recv, GROUP_PING_INTERVAL * 3)) {\n            delpeer(g_c, groupnumber, i);\n        }\n\n        if (g->group == NULL || i >= g->numpeers)\n            break;\n    }\n\n    return 0;\n}\n\n/* Send current name (set in messenger) to all online groups.\n */\nvoid send_name_all_groups(Group_Chats *g_c)\n{\n    unsigned int i;\n\n    for (i = 0; i < g_c->num_chats; ++i) {\n        Group_c *g = get_group_c(g_c, i);\n\n        if (!g)\n            continue;\n\n        if (g->status == GROUPCHAT_STATUS_CONNECTED) {\n            group_name_send(g_c, i, g_c->m->name, g_c->m->name_length);\n        }\n    }\n}\n\n/* Create new groupchat instance. */\nGroup_Chats *new_groupchats(Messenger *m)\n{\n    if (!m)\n        return NULL;\n\n    Group_Chats *temp = calloc(1, sizeof(Group_Chats));\n\n    if (temp == NULL)\n        return NULL;\n\n    temp->m = m;\n    temp->fr_c = m->fr_c;\n    m->group_chat_object = temp;\n    m_callback_group_invite(m, &handle_friend_invite_packet);\n\n    return temp;\n}\n\n/* main groupchats loop. */\nvoid do_groupchats(Group_Chats *g_c)\n{\n    unsigned int i;\n\n    for (i = 0; i < g_c->num_chats; ++i) {\n        Group_c *g = get_group_c(g_c, i);\n\n        if (!g)\n            continue;\n\n        if (g->status == GROUPCHAT_STATUS_CONNECTED) {\n            connect_to_closest(g_c, i);\n            ping_groupchat(g_c, i);\n            groupchat_clear_timedout(g_c, i);\n        }\n    }\n\n    //TODO\n}\n\n/* Free everything related with group chats. */\nvoid kill_groupchats(Group_Chats *g_c)\n{\n    unsigned int i;\n\n    for (i = 0; i < g_c->num_chats; ++i) {\n        del_groupchat(g_c, i);\n    }\n\n    m_callback_group_invite(g_c->m, NULL);\n    g_c->m->group_chat_object = 0;\n    free(g_c);\n}\n\n/* Return the number of chats in the instance m.\n * You should use this to determine how much memory to allocate\n * for copy_chatlist.\n */\nuint32_t count_chatlist(Group_Chats *g_c)\n{\n    uint32_t ret = 0;\n    uint32_t i;\n\n    for (i = 0; i < g_c->num_chats; i++) {\n        if (g_c->chats[i].status != GROUPCHAT_STATUS_NONE) {\n            ret++;\n        }\n    }\n\n    return ret;\n}\n\n/* Copy a list of valid chat IDs into the array out_list.\n * If out_list is NULL, returns 0.\n * Otherwise, returns the number of elements copied.\n * If the array was too small, the contents\n * of out_list will be truncated to list_size. */\nuint32_t copy_chatlist(Group_Chats *g_c, int32_t *out_list, uint32_t list_size)\n{\n    if (!out_list) {\n        return 0;\n    }\n\n    if (g_c->num_chats == 0) {\n        return 0;\n    }\n\n    uint32_t i, ret = 0;\n\n    for (i = 0; i < g_c->num_chats; ++i) {\n        if (ret >= list_size) {\n            break;  /* Abandon ship */\n        }\n\n        if (g_c->chats[i].status > GROUPCHAT_STATUS_NONE) {\n            out_list[ret] = i;\n            ret++;\n        }\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "toxcore/group.h",
    "content": "/* group.h\n *\n * Slightly better groupchats implementation.\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n\n#ifndef GROUP_H\n#define GROUP_H\n\n#include \"Messenger.h\"\n\nenum {\n    GROUPCHAT_STATUS_NONE,\n    GROUPCHAT_STATUS_VALID,\n    GROUPCHAT_STATUS_CONNECTED\n};\n\nenum {\n    GROUPCHAT_TYPE_TEXT,\n    GROUPCHAT_TYPE_AV\n};\n\n#define MAX_LOSSY_COUNT 256\n\ntypedef struct {\n    uint8_t     real_pk[crypto_box_PUBLICKEYBYTES];\n    uint8_t     temp_pk[crypto_box_PUBLICKEYBYTES];\n\n    uint64_t    last_recv;\n    uint32_t    last_message_number;\n\n    uint8_t     nick[MAX_NAME_LENGTH];\n    uint8_t     nick_len;\n\n    uint16_t peer_number;\n\n    uint8_t  recv_lossy[MAX_LOSSY_COUNT];\n    uint16_t bottom_lossy_number, top_lossy_number;\n\n    void *object;\n} Group_Peer;\n\n#define DESIRED_CLOSE_CONNECTIONS 4\n#define MAX_GROUP_CONNECTIONS 16\n#define GROUP_IDENTIFIER_LENGTH (1 + crypto_box_KEYBYTES) /* type + crypto_box_KEYBYTES so we can use new_symmetric_key(...) to fill it */\n\nenum {\n    GROUPCHAT_CLOSE_NONE,\n    GROUPCHAT_CLOSE_CONNECTION,\n    GROUPCHAT_CLOSE_ONLINE\n};\n\ntypedef struct {\n    uint8_t status;\n\n    Group_Peer *group;\n    uint32_t numpeers;\n\n    struct {\n        uint8_t type; /* GROUPCHAT_CLOSE_* */\n        uint8_t closest;\n        uint32_t number;\n        uint16_t group_number;\n    } close[MAX_GROUP_CONNECTIONS];\n\n    uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n    struct {\n        uint8_t entry;\n        uint8_t real_pk[crypto_box_PUBLICKEYBYTES];\n        uint8_t temp_pk[crypto_box_PUBLICKEYBYTES];\n    } closest_peers[DESIRED_CLOSE_CONNECTIONS];\n    uint8_t changed;\n\n    uint8_t identifier[GROUP_IDENTIFIER_LENGTH];\n\n    uint8_t title[MAX_NAME_LENGTH];\n    uint8_t title_len;\n\n    uint32_t message_number;\n    uint16_t lossy_message_number;\n    uint16_t peer_number;\n\n    uint64_t last_sent_ping;\n\n    int number_joined; /* friendcon_id of person that invited us to the chat. (-1 means none) */\n\n    void *object;\n\n    void (*peer_on_join)(void *, int, int);\n    void (*peer_on_leave)(void *, int, int, void *);\n    void (*group_on_delete)(void *, int);\n} Group_c;\n\ntypedef struct {\n    Messenger *m;\n    Friend_Connections *fr_c;\n\n    Group_c *chats;\n    uint32_t num_chats;\n\n    void (*invite_callback)(Messenger *m, int32_t, uint8_t, const uint8_t *, uint16_t, void *);\n    void *invite_callback_userdata;\n    void (*message_callback)(Messenger *m, int, int, const uint8_t *, uint16_t, void *);\n    void *message_callback_userdata;\n    void (*action_callback)(Messenger *m, int, int, const uint8_t *, uint16_t, void *);\n    void *action_callback_userdata;\n    void (*peer_namelistchange)(Messenger *m, int, int, uint8_t, void *);\n    void *group_namelistchange_userdata;\n    void (*title_callback)(Messenger *m, int, int, const uint8_t *, uint8_t, void *);\n    void *title_callback_userdata;\n\n    struct {\n        int (*function)(void *, int, int, void *, const uint8_t *, uint16_t);\n    } lossy_packethandlers[256];\n} Group_Chats;\n\n/* Set the callback for group invites.\n *\n *  Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata)\n *\n *  data of length is what needs to be passed to join_groupchat().\n */\nvoid g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, int32_t, uint8_t, const uint8_t *,\n                             uint16_t, void *), void *userdata);\n\n/* Set the callback for group messages.\n *\n *  Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)\n */\nvoid g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t,\n                              void *), void *userdata);\n\n/* Set the callback for group actions.\n *\n *  Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata)\n */\nvoid g_callback_group_action(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint16_t,\n                             void *), void *userdata);\n\n/* Set callback function for title changes.\n *\n * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata)\n * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group)\n */\nvoid g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, int, int, const uint8_t *, uint8_t,\n                            void *), void *userdata);\n\n/* Set callback function for peer name list changes.\n *\n * It gets called every time the name list changes(new peer/name, deleted peer)\n *  Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata)\n */\nenum {\n    CHAT_CHANGE_PEER_ADD,\n    CHAT_CHANGE_PEER_DEL,\n    CHAT_CHANGE_PEER_NAME,\n};\nvoid g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *),\n                                     void *userdata);\n\n/* Creates a new groupchat and puts it in the chats array.\n *\n * type is one of GROUPCHAT_TYPE_*\n *\n * return group number on success.\n * return -1 on failure.\n */\nint add_groupchat(Group_Chats *g_c, uint8_t type);\n\n/* Delete a groupchat from the chats array.\n *\n * return 0 on success.\n * return -1 if failure.\n */\nint del_groupchat(Group_Chats *g_c, int groupnumber);\n\n/* Copy the public key of peernumber who is in groupnumber to pk.\n * pk must be crypto_box_PUBLICKEYBYTES long.\n *\n * returns 0 on success\n * returns -1 on failure\n */\nint group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk);\n\n/* Copy the name of peernumber who is in groupnumber to name.\n * name must be at least MAX_NAME_LENGTH long.\n *\n * return length of name if success\n * return -1 if failure\n */\nint group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name);\n\n/* invite friendnumber to groupnumber\n * return 0 on success\n * return -1 on failure\n */\nint invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber);\n\n/* Join a group (you need to have been invited first.)\n *\n * expected_type is the groupchat type we expect the chat we are joining is.\n *\n * returns group number on success\n * returns -1 on failure.\n */\nint join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length);\n\n/* send a group message\n * return 0 on success\n * return -1 on failure\n */\nint group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length);\n\n/* send a group action\n * return 0 on success\n * return -1 on failure\n */\nint group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length);\n\n/* set the group's title, limited to MAX_NAME_LENGTH\n * return 0 on success\n * return -1 on failure\n */\nint group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len);\n\n\n/* Get group title from groupnumber and put it in title.\n * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes.\n *\n *  return length of copied title if success.\n *  return -1 if failure.\n */\nint group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title, uint32_t max_length);\n\n/* Return the number of peers in the group chat on success.\n * return -1 on failure\n */\nint group_number_peers(const Group_Chats *g_c, int groupnumber);\n\n/* return 1 if the peernumber corresponds to ours.\n * return 0 on failure.\n */\nunsigned int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber);\n\n/* List all the peers in the group chat.\n *\n * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array.\n *\n * Copies the lengths of the names to lengths[length]\n *\n * returns the number of peers on success.\n *\n * return -1 on failure.\n */\nint group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[],\n                uint16_t length);\n\n/* Set handlers for custom lossy packets.\n *\n * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed.\n *\n * 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)\n */\nvoid group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *,\n                                        const uint8_t *, uint16_t));\n\n/* High level function to send custom lossy packets.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length);\n\n/* Return the number of chats in the instance m.\n * You should use this to determine how much memory to allocate\n * for copy_chatlist.\n */\nuint32_t count_chatlist(Group_Chats *g_c);\n\n/* Copy a list of valid chat IDs into the array out_list.\n * If out_list is NULL, returns 0.\n * Otherwise, returns the number of elements copied.\n * If the array was too small, the contents\n * of out_list will be truncated to list_size. */\nuint32_t copy_chatlist(Group_Chats *g_c, int32_t *out_list, uint32_t list_size);\n\n/* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is.\n *\n * return -1 on failure.\n * return type on success.\n */\nint group_get_type(const Group_Chats *g_c, int groupnumber);\n\n/* Send current name (set in messenger) to all online groups.\n */\nvoid send_name_all_groups(Group_Chats *g_c);\n\n/* Set the object that is tied to the group chat.\n *\n * return 0 on success.\n * return -1 on failure\n */\nint group_set_object(const Group_Chats *g_c, int groupnumber, void *object);\n\n/* Set the object that is tied to the group peer.\n *\n * return 0 on success.\n * return -1 on failure\n */\nint group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object);\n\n/* Return the object tide to the group chat previously set by group_set_object.\n *\n * return NULL on failure.\n * return object on success.\n */\nvoid *group_get_object(const Group_Chats *g_c, int groupnumber);\n\n/* Return the object tide to the group chat peer previously set by group_peer_set_object.\n *\n * return NULL on failure.\n * return object on success.\n */\nvoid *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber);\n\n/* Set a function to be called when a new peer joins a group chat.\n *\n * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber)\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int));\n\n/* Set a function to be called when a peer leaves a group chat.\n *\n * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object))\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *));\n\n/* Set a function to be called when the group chat is deleted.\n *\n * Function(void *group object (set with group_set_object), int groupnumber)\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int));\n\n/* Create new groupchat instance. */\nGroup_Chats *new_groupchats(Messenger *m);\n\n/* main groupchats loop. */\nvoid do_groupchats(Group_Chats *g_c);\n\n/* Free everything related with group chats. */\nvoid kill_groupchats(Group_Chats *g_c);\n\n#endif\n"
  },
  {
    "path": "toxcore/list.c",
    "content": "/* list.h\n *\n * Simple struct with functions to create a list which associates ids with data\n * -Allows for finding ids associated with data such as IPs or public keys in a short time\n * -Should only be used if there are relatively few add/remove calls to the list\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#include \"list.h\"\n\n/* Basically, the elements in the list are placed in order so that they can be searched for easily\n * -each element is seen as a big-endian integer when ordering them\n * -the ids array is maintained so that each id always matches\n * -the search algorithm cuts down the time to find the id associated with a piece of data\n *   at the cost of slow add/remove functions for large lists\n * -Starts at 1/2 of the array, compares the element in the array with the data,\n *   then moves +/- 1/4 of the array depending on whether the value is greater or lower,\n *   then +- 1/8, etc, until the value is matched or its position where it should be in the array is found\n * -some considerations since the array size is never perfect\n */\n\n#define INDEX(i) (~i)\n\n/* Find data in list\n *\n * return value:\n *  >= 0 : index of data in array\n *  < 0  : no match, returns index (return value is INDEX(index)) where\n *         the data should be inserted\n */\nstatic int find(const BS_LIST *list, const uint8_t *data)\n{\n    //should work well, but could be improved\n    if (list->n == 0) {\n        return INDEX(0);\n    }\n\n    uint32_t i = list->n / 2; //current position in the array\n    uint32_t delta = i / 2;   //how much we move in the array\n\n    if (!delta) {\n        delta = 1;\n    }\n\n    int d = -1; //used to determine if closest match is found\n    //closest match is found if we move back to where we have already been\n\n    while (1) {\n        int r = memcmp(data, list->data + list->element_size * i, list->element_size);\n\n        if (r == 0) {\n            return i;\n        }\n\n        if (r > 0) {\n            //data is greater\n            //move down\n            i += delta;\n\n            if (d == 0 || i == list->n) {\n                //reached bottom of list, or closest match\n                return INDEX(i);\n            }\n\n            delta = (delta) / 2;\n\n            if (delta == 0) {\n                delta = 1;\n                d = 1;\n            }\n        } else {\n            //data is smaller\n            if (d == 1 || i == 0) {\n                //reached top or list or closest match\n                return INDEX(i);\n            }\n\n            //move up\n            i -= delta;\n\n            delta = (delta) / 2;\n\n            if (delta == 0) {\n                delta = 1;\n                d = 0;\n            }\n        }\n    }\n}\n\n/* Resized the list list\n *\n * return value:\n *  1 : success\n *  0 : failure\n */\nstatic int resize(BS_LIST *list, uint32_t new_size)\n{\n    void *p;\n\n    p = realloc(list->data, list->element_size * new_size);\n\n    if (!p) {\n        return 0;\n    } else {\n        list->data = p;\n    }\n\n    p = realloc(list->ids, sizeof(int) * new_size);\n\n    if (!p) {\n        return 0;\n    } else {\n        list->ids = p;\n    }\n\n    return 1;\n}\n\n\nint bs_list_init(BS_LIST *list, uint32_t element_size, uint32_t initial_capacity)\n{\n    //set initial values\n    list->n = 0;\n    list->element_size = element_size;\n    list->capacity = 0;\n    list->data = NULL;\n    list->ids = NULL;\n\n    if (initial_capacity != 0) {\n        if (!resize(list, initial_capacity)) {\n            return 0;\n        }\n    }\n\n    list->capacity = initial_capacity;\n\n    return 1;\n}\n\nvoid bs_list_free(BS_LIST *list)\n{\n    //free both arrays\n    free(list->data);\n    free(list->ids);\n}\n\nint bs_list_find(const BS_LIST *list, const uint8_t *data)\n{\n    int r = find(list, data);\n\n    //return only -1 and positive values\n    if (r < 0) {\n        return -1;\n    }\n\n    return list->ids[r];\n}\n\nint bs_list_add(BS_LIST *list, const uint8_t *data, int id)\n{\n    //find where the new element should be inserted\n    //see: return value of find()\n    int i = find(list, data);\n\n    if (i >= 0) {\n        //already in list\n        return 0;\n    }\n\n    i = ~i;\n\n    //increase the size of the arrays if needed\n    if (list->n == list->capacity) {\n        // 1.5 * n + 1\n        const uint32_t new_capacity = list->n + list->n / 2 + 1;\n\n        if (!resize(list, new_capacity)) {\n            return 0;\n        }\n\n        list->capacity = new_capacity;\n    }\n\n    //insert data to element array\n    memmove(list->data + (i + 1) * list->element_size, list->data + i * list->element_size,\n            (list->n - i) * list->element_size);\n    memcpy(list->data + i * list->element_size, data, list->element_size);\n\n    //insert id to id array\n    memmove(&list->ids[i + 1], &list->ids[i], (list->n - i) * sizeof(int));\n    list->ids[i] = id;\n\n    //increase n\n    list->n++;\n\n    return 1;\n}\n\nint bs_list_remove(BS_LIST *list, const uint8_t *data, int id)\n{\n    int i = find(list, data);\n\n    if (i < 0) {\n        return 0;\n    }\n\n    if (list->ids[i] != id) {\n        //this should never happen\n        return 0;\n    }\n\n    //decrease the size of the arrays if needed\n    if (list->n < list->capacity / 2) {\n        const uint32_t new_capacity = list->capacity / 2;\n\n        if (resize(list, new_capacity)) {\n            list->capacity = new_capacity;\n        }\n    }\n\n    list->n--;\n\n    memmove(list->data + i * list->element_size, list->data + (i + 1) * list->element_size,\n            (list->n - i) * list->element_size);\n    memmove(&list->ids[i], &list->ids[i + 1], (list->n - i) * sizeof(int));\n\n    return 1;\n}\n\nint bs_list_trim(BS_LIST *list)\n{\n    if (!resize(list, list->n)) {\n        return 0;\n    }\n\n    list->capacity = list->n;\n    return 1;\n}\n"
  },
  {
    "path": "toxcore/list.h",
    "content": "/* list.h\n *\n * Simple struct with functions to create a list which associates ids with data\n * -Allows for finding ids associated with data such as IPs or public keys in a short time\n * -Should only be used if there are relatively few add/remove calls to the list\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef LIST_H\n#define LIST_H\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\ntypedef struct {\n    uint32_t n; //number of elements\n    uint32_t capacity; //number of elements memory is allocated for\n    uint32_t element_size; //size of the elements\n    uint8_t *data; //array of elements\n    int *ids; //array of element ids\n} BS_LIST;\n\n/* Initialize a list, element_size is the size of the elements in the list and\n * initial_capacity is the number of elements the memory will be initially allocated for\n *\n * return value:\n *  1 : success\n *  0 : failure\n */\nint bs_list_init(BS_LIST *list, uint32_t element_size, uint32_t initial_capacity);\n\n/* Free a list initiated with list_init */\nvoid bs_list_free(BS_LIST *list);\n\n/* Retrieve the id of an element in the list\n *\n * return value:\n *  >= 0 : id associated with data\n *  -1   : failure\n */\nint bs_list_find(const BS_LIST *list, const uint8_t *data);\n\n/* Add an element with associated id to the list\n *\n * return value:\n *  1 : success\n *  0 : failure (data already in list)\n */\nint bs_list_add(BS_LIST *list, const uint8_t *data, int id);\n\n/* Remove element from the list\n *\n * return value:\n *  1 : success\n *  0 : failure (element not found or id does not match)\n */\nint bs_list_remove(BS_LIST *list, const uint8_t *data, int id);\n\n/* Removes the memory overhead\n *\n * return value:\n *  1 : success\n *  0 : failure\n */\nint bs_list_trim(BS_LIST *list);\n\n#endif\n"
  },
  {
    "path": "toxcore/logger.c",
    "content": "/*  logger.c\n *\n *  Copyright (C) 2013, 2015 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif /* HAVE_CONFIG_H */\n\n#include \"logger.h\"\n#include \"crypto_core.h\" /* for random_int() */\n\n#include <stdio.h>\n#include <errno.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <time.h>\n#include <pthread.h>\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n#   define getpid() ((unsigned) GetCurrentProcessId())\n#   define SFILE(FILE__M) (strrchr(FILE__M, '\\\\') ? strrchr(FILE__M, '\\\\') + 1 : FILE__M)\n#   define WIN_CR \"\\r\"\n#else\n#   define SFILE(FILE__M) (strrchr(FILE__M, '/') ? strrchr(FILE__M, '/') + 1 : FILE__M)\n#   define WIN_CR \"\"\n#endif\n\n\nstruct Logger {\n    FILE *log_file;\n    LOG_LEVEL level;\n    uint64_t start_time; /* Time when lib loaded */\n    char *id;\n\n    /* Allocate these once */\n    char *tstr;\n    char *posstr;\n    char *msg;\n\n    /* For thread synchronisation */\n    pthread_mutex_t mutex[1];\n};\n\nLogger *global = NULL;\n\nconst char *LOG_LEVEL_STR [] = {\n    [LOG_TRACE]   = \"TRACE\",\n    [LOG_DEBUG]   = \"DEBUG\",\n    [LOG_INFO]    = \"INFO\" ,\n    [LOG_WARNING] = \"WARN\" ,\n    [LOG_ERROR]   = \"ERROR\",\n};\n\nchar *strtime(char *dest, size_t max_len)\n{\n    time_t timer;\n    struct tm *tm_info;\n\n    time(&timer);\n    tm_info = localtime(&timer);\n\n    strftime(dest, max_len, \"%m:%d %H:%M:%S\", tm_info);\n    return dest;\n}\n\n\n/**\n * Public Functions\n */\nLogger *logger_new (const char *file_name, LOG_LEVEL level, const char *id)\n{\n#ifndef TOX_LOGGER /* Disabled */\n    return NULL;\n#endif\n\n    Logger *retu = calloc(1, sizeof(Logger));\n\n    if (!retu)\n        return NULL;\n\n    if (pthread_mutex_init(retu->mutex, NULL) != 0) {\n        free(retu);\n        return NULL;\n    }\n\n    if (!(retu->log_file = fopen(file_name, \"ab\"))) {\n        fprintf(stderr, \"Error opening logger file: %s; info: %s\" WIN_CR \"\\n\", file_name, strerror(errno));\n        free(retu);\n        pthread_mutex_destroy(retu->mutex);\n        return NULL;\n    }\n\n    if (!(retu->tstr = calloc(16, sizeof (char))) ||\n            !(retu->posstr = calloc(300, sizeof (char))) ||\n            !(retu->msg = calloc(4096, sizeof (char))))\n        goto FAILURE;\n\n    if (id) {\n        if (!(retu->id = calloc(strlen(id) + 1, 1)))\n            goto FAILURE;\n\n        strcpy(retu->id, id);\n    } else {\n        if (!(retu->id = malloc(8)))\n            goto FAILURE;\n\n        snprintf(retu->id, 8, \"%u\", random_int());\n    }\n\n    retu->level = level;\n    retu->start_time = current_time_monotonic();\n\n    fprintf(retu->log_file, \"Successfully created and running logger id: %s; time: %s\" WIN_CR \"\\n\",\n            retu->id, strtime(retu->tstr, 16));\n\n    return retu;\n\nFAILURE:\n    fprintf(stderr, \"Failed to create logger!\" WIN_CR \"\\n\");\n    pthread_mutex_destroy(retu->mutex);\n    fclose(retu->log_file);\n    free(retu->tstr);\n    free(retu->posstr);\n    free(retu->msg);\n    free(retu->id);\n    free(retu);\n    return NULL;\n}\n\nvoid logger_kill(Logger *log)\n{\n#ifndef TOX_LOGGER /* Disabled */\n    return;\n#endif\n\n    if (!log)\n        return;\n\n    pthread_mutex_lock(log->mutex);\n    free(log->id);\n    free(log->tstr);\n    free(log->posstr);\n    free(log->msg);\n\n    if (fclose(log->log_file) != 0)\n        perror(\"Could not close log file\");\n\n    pthread_mutex_unlock(log->mutex);\n    pthread_mutex_destroy(log->mutex);\n\n    free(log);\n}\n\nvoid logger_kill_global(void)\n{\n    logger_kill(global);\n    global = NULL;\n}\n\nvoid logger_set_global(Logger *log)\n{\n#ifndef TOX_LOGGER /* Disabled */\n    return;\n#endif\n\n    global = log;\n}\n\nLogger *logger_get_global(void)\n{\n#ifndef TOX_LOGGER /* Disabled */\n    return NULL;\n#endif\n\n    return global;\n}\n\nvoid logger_write (Logger *log, LOG_LEVEL level, const char *file, int line, const char *format, ...)\n{\n#ifndef TOX_LOGGER /* Disabled */\n    return;\n#endif\n\n    static const char *logger_format =\n        \"%s  \"          /* Logger id string */\n        \"%-16s\"         /* Time string of format: %m:%d %H:%M:%S */\n        \"%-12u \"        /* Thread id */\n        \"%-5s  \"        /* Logger lever string */\n        \"%-20s \"        /* File:line string */\n        \"- %s\"          /* Output message */\n        WIN_CR \"\\n\";    /* Every new print new line */\n\n\n    Logger *this_log = log ? log : global;\n\n    if (!this_log)\n        return;\n\n    /* Don't print levels lesser than set one */\n    if (this_log->level > level)\n        return;\n\n    pthread_mutex_lock(this_log->mutex);\n\n    /* Set position str */\n    snprintf(this_log->posstr, 300, \"%s:%d\", SFILE(file), line);\n\n    /* Set message */\n    va_list args;\n    va_start (args, format);\n    vsnprintf(this_log->msg, 4096, format, args);\n    va_end (args);\n\n    fprintf(this_log->log_file, logger_format, this_log->id, strtime(this_log->tstr, 16), pthread_self(),\n            LOG_LEVEL_STR[level], this_log->posstr, this_log->msg);\n    fflush(this_log->log_file);\n\n    pthread_mutex_unlock(this_log->mutex);\n}\n"
  },
  {
    "path": "toxcore/logger.h",
    "content": "/*  logger.h\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n\n#ifndef TOXLOGGER_H\n#define TOXLOGGER_H\n\n#include <string.h>\n\n/* In case these are undefined; define 'empty' */\n#ifndef LOGGER_OUTPUT_FILE\n#   define LOGGER_OUTPUT_FILE \"\"\n#endif\n\n#ifndef LOGGER_LEVEL\n#   define LOGGER_LEVEL LOG_ERROR\n#endif\n\n\ntypedef enum {\n    LOG_TRACE,\n    LOG_DEBUG,\n    LOG_INFO,\n    LOG_WARNING,\n    LOG_ERROR\n} LOG_LEVEL;\n\ntypedef struct Logger Logger;\n\n/**\n * Set 'level' as the lowest printable level. If id == NULL, random number is used.\n */\nLogger *logger_new (const char *file_name, LOG_LEVEL level, const char *id);\n\nvoid logger_kill (Logger *log);\nvoid logger_kill_global (void);\n\n/**\n * Global logger setter and getter.\n */\nvoid logger_set_global (Logger *log);\nLogger *logger_get_global (void);\n\n/**\n * Main write function. If logging disabled does nothing. If log == NULL uses global logger.\n */\nvoid logger_write (Logger *log, LOG_LEVEL level, const char *file, int line, const char *format, ...);\n\n\n/* To do some checks or similar only when logging, use this */\n#ifdef TOX_LOGGER\n#   define LOGGER_SCOPE(__SCOPE_DO__) do { __SCOPE_DO__ } while(0)\n#   define LOGGER_WRITE(log, level, format, ...) \\\n            logger_write(log, level, __FILE__, __LINE__, format, ##__VA_ARGS__)\n#else\n/* #   warning \"Logging disabled\" */\n#   define LOGGER_SCOPE(__SCOPE_DO__) do {} while(0)\n#   define LOGGER_WRITE(log, level, format, ...) do {} while(0)\n#endif /* TOX_LOGGER */\n\n/* To log with an logger */\n#define LOGGER_TRACE_(log, format, ...) LOGGER_WRITE(log, LOG_TRACE, format, ##__VA_ARGS__)\n#define LOGGER_DEBUG_(log, format, ...) LOGGER_WRITE(log, LOG_DEBUG, format, ##__VA_ARGS__)\n#define LOGGER_INFO_(log, format, ...) LOGGER_WRITE(log, LOG_INFO, format, ##__VA_ARGS__)\n#define LOGGER_WARNING_(log, format, ...) LOGGER_WRITE(log, LOG_WARNING, format, ##__VA_ARGS__)\n#define LOGGER_ERROR_(log, format, ...) LOGGER_WRITE(log, LOG_ERROR, format, ##__VA_ARGS__)\n\n/* To log with the global logger */\n#define LOGGER_TRACE(format, ...) LOGGER_TRACE_(NULL, format, ##__VA_ARGS__)\n#define LOGGER_DEBUG(format, ...) LOGGER_DEBUG_(NULL, format, ##__VA_ARGS__)\n#define LOGGER_INFO(format, ...) LOGGER_INFO_(NULL, format, ##__VA_ARGS__)\n#define LOGGER_WARNING(format, ...) LOGGER_WARNING_(NULL, format, ##__VA_ARGS__)\n#define LOGGER_ERROR(format, ...) LOGGER_ERROR_(NULL, format, ##__VA_ARGS__)\n\n\n#endif /* TOXLOGGER_H */\n"
  },
  {
    "path": "toxcore/misc_tools.h",
    "content": "/* misc_tools.h\n *\n * Miscellaneous functions and data structures for doing random things.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef MISC_TOOLS_H\n#define MISC_TOOLS_H\n\n/****************************Algorithms***************************\n * Macro/generic definitions for useful algorithms\n *****************************************************************/\n\n/* Creates a new quick_sort implementation for arrays of the specified type.\n * For a type T (eg: int, char), creates a function named T_quick_sort.\n *\n * Quick Sort: Complexity O(nlogn)\n * arr   - the array to sort\n * n     - the sort index (should be called with n = length(arr))\n * cmpfn - a function that compares two values of type type.\n *         Must return -1, 0, 1 for a < b, a == b, and a > b respectively.\n */\n/* Must be called in the header file. */\n#define declare_quick_sort(type) \\\nvoid type##_quick_sort(type *arr, int n, int (*cmpfn)(type, type));\n\n/* Must be called in the C file. */\n#define make_quick_sort(type) \\\nvoid type##_quick_sort(type *arr, int n, int (*cmpfn)(type, type)) \\\n{ \\\n    if ((n) < 2) \\\n        return; \\\n    type _p_ = (arr)[(n) / 2]; \\\n    type *_l_ = (arr); \\\n    type *_r_ = (arr) + n - 1; \\\n    while (_l_ <= _r_) { \\\n        if (cmpfn(*_l_, _p_) == -1) { \\\n            ++_l_; \\\n            continue; \\\n        } \\\n        if (cmpfn(*_r_, _p_) == 1) { \\\n            --_r_; \\\n            continue; \\\n        } \\\n        type _t_ = *_l_; \\\n        *_l_++ = *_r_; \\\n        *_r_-- = _t_; \\\n    } \\\n    type##_quick_sort((arr), _r_ - (arr) + 1, cmpfn); \\\n    type##_quick_sort(_l_, (arr) + n - _l_, cmpfn); \\\n}\n\n#endif // MISC_TOOLS_H\n"
  },
  {
    "path": "toxcore/net_crypto.c",
    "content": "/* net_crypto.c\n *\n * Functions for the core network crypto.\n *\n * NOTE: This code has to be perfect. We don't mess around with encryption.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"net_crypto.h\"\n#include \"util.h\"\n#include \"math.h\"\n#include \"logger.h\"\n\nstatic uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id)\n{\n    if ((uint32_t)crypt_connection_id >= c->crypto_connections_length)\n        return 1;\n\n    if (c->crypto_connections == NULL)\n        return 1;\n\n    if (c->crypto_connections[crypt_connection_id].status == CRYPTO_CONN_NO_CONNECTION)\n        return 1;\n\n    return 0;\n}\n\n/* cookie timeout in seconds */\n#define COOKIE_TIMEOUT 15\n#define COOKIE_DATA_LENGTH (crypto_box_PUBLICKEYBYTES * 2)\n#define COOKIE_CONTENTS_LENGTH (sizeof(uint64_t) + COOKIE_DATA_LENGTH)\n#define COOKIE_LENGTH (crypto_box_NONCEBYTES + COOKIE_CONTENTS_LENGTH + crypto_box_MACBYTES)\n\n#define COOKIE_REQUEST_PLAIN_LENGTH (COOKIE_DATA_LENGTH + sizeof(uint64_t))\n#define COOKIE_REQUEST_LENGTH (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + COOKIE_REQUEST_PLAIN_LENGTH + crypto_box_MACBYTES)\n#define COOKIE_RESPONSE_LENGTH (1 + crypto_box_NONCEBYTES + COOKIE_LENGTH + sizeof(uint64_t) + crypto_box_MACBYTES)\n\n/* Create a cookie request packet and put it in packet.\n * dht_public_key is the dht public key of the other\n *\n * packet must be of size COOKIE_REQUEST_LENGTH or bigger.\n *\n * return -1 on failure.\n * return COOKIE_REQUEST_LENGTH on success.\n */\nstatic int create_cookie_request(const Net_Crypto *c, uint8_t *packet, uint8_t *dht_public_key, uint64_t number,\n                                 uint8_t *shared_key)\n{\n    uint8_t plain[COOKIE_REQUEST_PLAIN_LENGTH];\n    uint8_t padding[crypto_box_PUBLICKEYBYTES] = {0};\n\n    memcpy(plain, c->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(plain + crypto_box_PUBLICKEYBYTES, padding, crypto_box_PUBLICKEYBYTES);\n    memcpy(plain + (crypto_box_PUBLICKEYBYTES * 2), &number, sizeof(uint64_t));\n\n    DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key);\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    new_nonce(nonce);\n    packet[0] = NET_PACKET_COOKIE_REQUEST;\n    memcpy(packet + 1, c->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);\n    int len = encrypt_data_symmetric(shared_key, nonce, plain, sizeof(plain),\n                                     packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);\n\n    if (len != COOKIE_REQUEST_PLAIN_LENGTH + crypto_box_MACBYTES)\n        return -1;\n\n    return (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + len);\n}\n\n/* Create cookie of length COOKIE_LENGTH from bytes of length COOKIE_DATA_LENGTH using encryption_key\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int create_cookie(uint8_t *cookie, const uint8_t *bytes, const uint8_t *encryption_key)\n{\n    uint8_t contents[COOKIE_CONTENTS_LENGTH];\n    uint64_t temp_time = unix_time();\n    memcpy(contents, &temp_time, sizeof(temp_time));\n    memcpy(contents + sizeof(temp_time), bytes, COOKIE_DATA_LENGTH);\n    new_nonce(cookie);\n    int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + crypto_box_NONCEBYTES);\n\n    if (len != COOKIE_LENGTH - crypto_box_NONCEBYTES)\n        return -1;\n\n    return 0;\n}\n\n/* Open cookie of length COOKIE_LENGTH to bytes of length COOKIE_DATA_LENGTH using encryption_key\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int open_cookie(uint8_t *bytes, const uint8_t *cookie, const uint8_t *encryption_key)\n{\n    uint8_t contents[COOKIE_CONTENTS_LENGTH];\n    int len = decrypt_data_symmetric(encryption_key, cookie, cookie + crypto_box_NONCEBYTES,\n                                     COOKIE_LENGTH - crypto_box_NONCEBYTES, contents);\n\n    if (len != sizeof(contents))\n        return -1;\n\n    uint64_t cookie_time;\n    memcpy(&cookie_time, contents, sizeof(cookie_time));\n    uint64_t temp_time = unix_time();\n\n    if (cookie_time + COOKIE_TIMEOUT < temp_time || temp_time < cookie_time)\n        return -1;\n\n    memcpy(bytes, contents + sizeof(cookie_time), COOKIE_DATA_LENGTH);\n    return 0;\n}\n\n\n/* Create a cookie response packet and put it in packet.\n * request_plain must be COOKIE_REQUEST_PLAIN_LENGTH bytes.\n * packet must be of size COOKIE_RESPONSE_LENGTH or bigger.\n *\n * return -1 on failure.\n * return COOKIE_RESPONSE_LENGTH on success.\n */\nstatic int create_cookie_response(const Net_Crypto *c, uint8_t *packet, const uint8_t *request_plain,\n                                  const uint8_t *shared_key, const uint8_t *dht_public_key)\n{\n    uint8_t cookie_plain[COOKIE_DATA_LENGTH];\n    memcpy(cookie_plain, request_plain, crypto_box_PUBLICKEYBYTES);\n    memcpy(cookie_plain + crypto_box_PUBLICKEYBYTES, dht_public_key, crypto_box_PUBLICKEYBYTES);\n    uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)];\n\n    if (create_cookie(plain, cookie_plain, c->secret_symmetric_key) != 0)\n        return -1;\n\n    memcpy(plain + COOKIE_LENGTH, request_plain + COOKIE_DATA_LENGTH, sizeof(uint64_t));\n    packet[0] = NET_PACKET_COOKIE_RESPONSE;\n    new_nonce(packet + 1);\n    int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + crypto_box_NONCEBYTES);\n\n    if (len != COOKIE_RESPONSE_LENGTH - (1 + crypto_box_NONCEBYTES))\n        return -1;\n\n    return COOKIE_RESPONSE_LENGTH;\n}\n\n/* Handle the cookie request packet of length length.\n * Put what was in the request in request_plain (must be of size COOKIE_REQUEST_PLAIN_LENGTH)\n * Put the key used to decrypt the request into shared_key (of size crypto_box_BEFORENMBYTES) for use in the response.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, uint8_t *shared_key,\n                                 uint8_t *dht_public_key, const uint8_t *packet, uint16_t length)\n{\n    if (length != COOKIE_REQUEST_LENGTH)\n        return -1;\n\n    memcpy(dht_public_key, packet + 1, crypto_box_PUBLICKEYBYTES);\n    DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key);\n    int len = decrypt_data_symmetric(shared_key, packet + 1 + crypto_box_PUBLICKEYBYTES,\n                                     packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, COOKIE_REQUEST_PLAIN_LENGTH + crypto_box_MACBYTES,\n                                     request_plain);\n\n    if (len != COOKIE_REQUEST_PLAIN_LENGTH)\n        return -1;\n\n    return 0;\n}\n\n/* Handle the cookie request packet (for raw UDP)\n */\nstatic int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Net_Crypto *c = object;\n    uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];\n\n    if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0)\n        return 1;\n\n    uint8_t data[COOKIE_RESPONSE_LENGTH];\n\n    if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data))\n        return 1;\n\n    if ((uint32_t)sendpacket(c->dht->net, source, data, sizeof(data)) != sizeof(data))\n        return 1;\n\n    return 0;\n}\n\n/* Handle the cookie request packet (for TCP)\n */\nstatic int tcp_handle_cookie_request(Net_Crypto *c, int connections_number, const uint8_t *packet, uint16_t length)\n{\n    uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];\n\n    if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0)\n        return -1;\n\n    uint8_t data[COOKIE_RESPONSE_LENGTH];\n\n    if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data))\n        return -1;\n\n    int ret = send_packet_tcp_connection(c->tcp_c, connections_number, data, sizeof(data));\n    return ret;\n}\n\n/* Handle the cookie request packet (for TCP oob packets)\n */\nstatic int tcp_oob_handle_cookie_request(const Net_Crypto *c, unsigned int tcp_connections_number,\n        const uint8_t *dht_public_key, const uint8_t *packet, uint16_t length)\n{\n    uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    uint8_t dht_public_key_temp[crypto_box_PUBLICKEYBYTES];\n\n    if (handle_cookie_request(c, request_plain, shared_key, dht_public_key_temp, packet, length) != 0)\n        return -1;\n\n    if (public_key_cmp(dht_public_key, dht_public_key_temp) != 0)\n        return -1;\n\n    uint8_t data[COOKIE_RESPONSE_LENGTH];\n\n    if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data))\n        return -1;\n\n    int ret = tcp_send_oob_packet(c->tcp_c, tcp_connections_number, dht_public_key, data, sizeof(data));\n    return ret;\n}\n\n/* Handle a cookie response packet of length encrypted with shared_key.\n * put the cookie in the response in cookie\n *\n * cookie must be of length COOKIE_LENGTH.\n *\n * return -1 on failure.\n * return COOKIE_LENGTH on success.\n */\nstatic int handle_cookie_response(uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint16_t length,\n                                  const uint8_t *shared_key)\n{\n    if (length != COOKIE_RESPONSE_LENGTH)\n        return -1;\n\n    uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)];\n    int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,\n                                     length - (1 + crypto_box_NONCEBYTES), plain);\n\n    if (len != sizeof(plain))\n        return -1;\n\n    memcpy(cookie, plain, COOKIE_LENGTH);\n    memcpy(number, plain + COOKIE_LENGTH, sizeof(uint64_t));\n    return COOKIE_LENGTH;\n}\n\n#define HANDSHAKE_PACKET_LENGTH (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES + COOKIE_LENGTH + crypto_box_MACBYTES)\n\n/* Create a handshake packet and put it in packet.\n * cookie must be COOKIE_LENGTH bytes.\n * packet must be of size HANDSHAKE_PACKET_LENGTH or bigger.\n *\n * return -1 on failure.\n * return HANDSHAKE_PACKET_LENGTH on success.\n */\nstatic int create_crypto_handshake(const Net_Crypto *c, uint8_t *packet, const uint8_t *cookie, const uint8_t *nonce,\n                                   const uint8_t *session_pk, const uint8_t *peer_real_pk, const uint8_t *peer_dht_pubkey)\n{\n    uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES + COOKIE_LENGTH];\n    memcpy(plain, nonce, crypto_box_NONCEBYTES);\n    memcpy(plain + crypto_box_NONCEBYTES, session_pk, crypto_box_PUBLICKEYBYTES);\n    crypto_hash_sha512(plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, cookie, COOKIE_LENGTH);\n    uint8_t cookie_plain[COOKIE_DATA_LENGTH];\n    memcpy(cookie_plain, peer_real_pk, crypto_box_PUBLICKEYBYTES);\n    memcpy(cookie_plain + crypto_box_PUBLICKEYBYTES, peer_dht_pubkey, crypto_box_PUBLICKEYBYTES);\n\n    if (create_cookie(plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES, cookie_plain,\n                      c->secret_symmetric_key) != 0)\n        return -1;\n\n    new_nonce(packet + 1 + COOKIE_LENGTH);\n    int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain),\n                           packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES);\n\n    if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES))\n        return -1;\n\n    packet[0] = NET_PACKET_CRYPTO_HS;\n    memcpy(packet + 1, cookie, COOKIE_LENGTH);\n\n    return HANDSHAKE_PACKET_LENGTH;\n}\n\n/* Handle a crypto handshake packet of length.\n * put the nonce contained in the packet in nonce,\n * the session public key in session_pk\n * the real public key of the peer in peer_real_pk\n * the dht public key of the peer in dht_public_key and\n * the cookie inside the encrypted part of the packet in cookie.\n *\n * if expected_real_pk isn't NULL it denotes the real public key\n * the packet should be from.\n *\n * nonce must be at least crypto_box_NONCEBYTES\n * session_pk must be at least crypto_box_PUBLICKEYBYTES\n * peer_real_pk must be at least crypto_box_PUBLICKEYBYTES\n * cookie must be at least COOKIE_LENGTH\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk,\n                                   uint8_t *dht_public_key, uint8_t *cookie, const uint8_t *packet, uint16_t length, const uint8_t *expected_real_pk)\n{\n    if (length != HANDSHAKE_PACKET_LENGTH)\n        return -1;\n\n    uint8_t cookie_plain[COOKIE_DATA_LENGTH];\n\n    if (open_cookie(cookie_plain, packet + 1, c->secret_symmetric_key) != 0)\n        return -1;\n\n    if (expected_real_pk)\n        if (public_key_cmp(cookie_plain, expected_real_pk) != 0)\n            return -1;\n\n    uint8_t cookie_hash[crypto_hash_sha512_BYTES];\n    crypto_hash_sha512(cookie_hash, packet + 1, COOKIE_LENGTH);\n\n    uint8_t plain[crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES + COOKIE_LENGTH];\n    int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH,\n                           packet + 1 + COOKIE_LENGTH + crypto_box_NONCEBYTES,\n                           HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + crypto_box_NONCEBYTES), plain);\n\n    if (len != sizeof(plain))\n        return -1;\n\n    if (sodium_memcmp(cookie_hash, plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,\n                      crypto_hash_sha512_BYTES) != 0)\n        return -1;\n\n    memcpy(nonce, plain, crypto_box_NONCEBYTES);\n    memcpy(session_pk, plain + crypto_box_NONCEBYTES, crypto_box_PUBLICKEYBYTES);\n    memcpy(cookie, plain + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_hash_sha512_BYTES, COOKIE_LENGTH);\n    memcpy(peer_real_pk, cookie_plain, crypto_box_PUBLICKEYBYTES);\n    memcpy(dht_public_key, cookie_plain + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);\n    return 0;\n}\n\n\nstatic Crypto_Connection *get_crypto_connection(const Net_Crypto *c, int crypt_connection_id)\n{\n    if (crypt_connection_id_not_valid(c, crypt_connection_id))\n        return 0;\n\n    return &c->crypto_connections[crypt_connection_id];\n}\n\n\n/* Associate an ip_port to a connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int add_ip_port_connection(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    if (ip_port.ip.family == AF_INET) {\n        if (!ipport_equal(&ip_port, &conn->ip_portv4) && LAN_ip(conn->ip_portv4.ip) != 0) {\n            if (!bs_list_add(&c->ip_port_list, (uint8_t *)&ip_port, crypt_connection_id))\n                return -1;\n\n            bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id);\n            conn->ip_portv4 = ip_port;\n            return 0;\n        }\n    } else if (ip_port.ip.family == AF_INET6) {\n        if (!ipport_equal(&ip_port, &conn->ip_portv6)) {\n            if (!bs_list_add(&c->ip_port_list, (uint8_t *)&ip_port, crypt_connection_id))\n                return -1;\n\n            bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id);\n            conn->ip_portv6 = ip_port;\n            return 0;\n        }\n    }\n\n    return -1;\n}\n\n/* Return the IP_Port that should be used to send packets to the other peer.\n *\n * return IP_Port with family 0 on failure.\n * return IP_Port on success.\n */\nIP_Port return_ip_port_connection(Net_Crypto *c, int crypt_connection_id)\n{\n    IP_Port empty;\n    empty.ip.family = 0;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return empty;\n\n    uint64_t current_time = unix_time();\n    _Bool v6 = 0, v4 = 0;\n\n    if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev4) > current_time) {\n        v4 = 1;\n    }\n\n    if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev6) > current_time) {\n        v6 = 1;\n    }\n\n    if (v4 && LAN_ip(conn->ip_portv4.ip) == 0) {\n        return conn->ip_portv4;\n    } else if (v6 && conn->ip_portv6.ip.family == AF_INET6) {\n        return conn->ip_portv6;\n    } else if (conn->ip_portv4.ip.family == AF_INET) {\n        return conn->ip_portv4;\n    } else {\n        return empty;\n    }\n}\n\n/* Sends a packet to the peer using the fastest route.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length)\n{\n//TODO TCP, etc...\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    int direct_send_attempt = 0;\n\n    pthread_mutex_lock(&conn->mutex);\n    IP_Port ip_port = return_ip_port_connection(c, crypt_connection_id);\n\n    //TODO: on bad networks, direct connections might not last indefinitely.\n    if (ip_port.ip.family != 0) {\n        _Bool direct_connected = 0;\n        crypto_connection_status(c, crypt_connection_id, &direct_connected, NULL);\n\n        if (direct_connected) {\n            if ((uint32_t)sendpacket(c->dht->net, ip_port, data, length) == length) {\n                pthread_mutex_unlock(&conn->mutex);\n                return 0;\n            } else {\n                pthread_mutex_unlock(&conn->mutex);\n                return -1;\n            }\n        }\n\n        //TODO: a better way of sending packets directly to confirm the others ip.\n        uint64_t current_time = unix_time();\n\n        if ((((UDP_DIRECT_TIMEOUT / 2) + conn->direct_send_attempt_time) > current_time && length < 96)\n                || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) {\n            if ((uint32_t)sendpacket(c->dht->net, ip_port, data, length) == length) {\n                direct_send_attempt = 1;\n                conn->direct_send_attempt_time = unix_time();\n            }\n        }\n    }\n\n    pthread_mutex_unlock(&conn->mutex);\n    pthread_mutex_lock(&c->tcp_mutex);\n    int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    pthread_mutex_lock(&conn->mutex);\n\n    if (ret == 0) {\n        conn->last_tcp_sent = current_time_monotonic();\n    }\n\n    pthread_mutex_unlock(&conn->mutex);\n\n    if (ret == 0 || direct_send_attempt) {\n        return 0;\n    }\n\n    return -1;\n}\n\n/** START: Array Related functions **/\n\n\n/* Return number of packets in array\n * Note that holes are counted too.\n */\nstatic uint32_t num_packets_array(const Packets_Array *array)\n{\n    return array->buffer_end - array->buffer_start;\n}\n\n/* Add data with packet number to array.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int add_data_to_buffer(Packets_Array *array, uint32_t number, const Packet_Data *data)\n{\n    if (number - array->buffer_start > CRYPTO_PACKET_BUFFER_SIZE)\n        return -1;\n\n    uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE;\n\n    if (array->buffer[num])\n        return -1;\n\n    Packet_Data *new_d = malloc(sizeof(Packet_Data));\n\n    if (new_d == NULL)\n        return -1;\n\n    memcpy(new_d, data, sizeof(Packet_Data));\n    array->buffer[num] = new_d;\n\n    if ((number - array->buffer_start) >= (array->buffer_end - array->buffer_start))\n        array->buffer_end = number + 1;\n\n    return 0;\n}\n\n/* Get pointer of data with packet number.\n *\n * return -1 on failure.\n * return 0 if data at number is empty.\n * return 1 if data pointer was put in data.\n */\nstatic int get_data_pointer(const Packets_Array *array, Packet_Data **data, uint32_t number)\n{\n    uint32_t num_spots = array->buffer_end - array->buffer_start;\n\n    if (array->buffer_end - number > num_spots || number - array->buffer_start >= num_spots)\n        return -1;\n\n    uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE;\n\n    if (!array->buffer[num])\n        return 0;\n\n    *data = array->buffer[num];\n    return 1;\n}\n\n/* Add data to end of array.\n *\n * return -1 on failure.\n * return packet number on success.\n */\nstatic int64_t add_data_end_of_buffer(Packets_Array *array, const Packet_Data *data)\n{\n    if (num_packets_array(array) >= CRYPTO_PACKET_BUFFER_SIZE)\n        return -1;\n\n    Packet_Data *new_d = malloc(sizeof(Packet_Data));\n\n    if (new_d == NULL)\n        return -1;\n\n    memcpy(new_d, data, sizeof(Packet_Data));\n    uint32_t id = array->buffer_end;\n    array->buffer[id % CRYPTO_PACKET_BUFFER_SIZE] = new_d;\n    ++array->buffer_end;\n    return id;\n}\n\n/* Read data from begginning of array.\n *\n * return -1 on failure.\n * return packet number on success.\n */\nstatic int64_t read_data_beg_buffer(Packets_Array *array, Packet_Data *data)\n{\n    if (array->buffer_end == array->buffer_start)\n        return -1;\n\n    uint32_t num = array->buffer_start % CRYPTO_PACKET_BUFFER_SIZE;\n\n    if (!array->buffer[num])\n        return -1;\n\n    memcpy(data, array->buffer[num], sizeof(Packet_Data));\n    uint32_t id = array->buffer_start;\n    ++array->buffer_start;\n    free(array->buffer[num]);\n    array->buffer[num] = NULL;\n    return id;\n}\n\n/* Delete all packets in array before number (but not number)\n *\n * return -1 on failure.\n * return 0 on success\n */\nstatic int clear_buffer_until(Packets_Array *array, uint32_t number)\n{\n    uint32_t num_spots = array->buffer_end - array->buffer_start;\n\n    if (array->buffer_end - number >= num_spots || number - array->buffer_start > num_spots)\n        return -1;\n\n    uint32_t i;\n\n    for (i = array->buffer_start; i != number; ++i) {\n        uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE;\n\n        if (array->buffer[num]) {\n            free(array->buffer[num]);\n            array->buffer[num] = NULL;\n        }\n    }\n\n    array->buffer_start = i;\n    return 0;\n}\n\nstatic int clear_buffer(Packets_Array *array)\n{\n    uint32_t i;\n\n    for (i = array->buffer_start; i != array->buffer_end; ++i) {\n        uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE;\n\n        if (array->buffer[num]) {\n            free(array->buffer[num]);\n            array->buffer[num] = NULL;\n        }\n    }\n\n    array->buffer_start = i;\n    return 0;\n}\n\n/* Set array buffer end to number.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int set_buffer_end(Packets_Array *array, uint32_t number)\n{\n    if ((number - array->buffer_start) > CRYPTO_PACKET_BUFFER_SIZE)\n        return -1;\n\n    if ((number - array->buffer_end) > CRYPTO_PACKET_BUFFER_SIZE)\n        return -1;\n\n    array->buffer_end = number;\n    return 0;\n}\n\n/* Create a packet request packet from recv_array and send_buffer_end into\n * data of length.\n *\n * return -1 on failure.\n * return length of packet on success.\n */\nstatic int generate_request_packet(uint8_t *data, uint16_t length, const Packets_Array *recv_array)\n{\n    if (length == 0)\n        return -1;\n\n    data[0] = PACKET_ID_REQUEST;\n\n    uint16_t cur_len = 1;\n\n    if (recv_array->buffer_start == recv_array->buffer_end)\n        return cur_len;\n\n    if (length <= cur_len)\n        return cur_len;\n\n    uint32_t i, n = 1;\n\n    for (i = recv_array->buffer_start; i != recv_array->buffer_end; ++i) {\n        uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE;\n\n        if (!recv_array->buffer[num]) {\n            data[cur_len] = n;\n            n = 0;\n            ++cur_len;\n\n            if (length <= cur_len)\n                return cur_len;\n\n        } else if (n == 255) {\n            data[cur_len] = 0;\n            n = 0;\n            ++cur_len;\n\n            if (length <= cur_len)\n                return cur_len;\n        }\n\n        ++n;\n    }\n\n    return cur_len;\n}\n\n/* Handle a request data packet.\n * Remove all the packets the other received from the array.\n *\n * return -1 on failure.\n * return number of requested packets on success.\n */\nstatic int handle_request_packet(Packets_Array *send_array, const uint8_t *data, uint16_t length,\n                                 uint64_t *latest_send_time, uint64_t rtt_time)\n{\n    if (length < 1)\n        return -1;\n\n    if (data[0] != PACKET_ID_REQUEST)\n        return -1;\n\n    if (length == 1)\n        return 0;\n\n    ++data;\n    --length;\n\n    uint32_t i, n = 1;\n    uint32_t requested = 0;\n\n    uint64_t temp_time = current_time_monotonic();\n    uint64_t l_sent_time = ~0;\n\n    for (i = send_array->buffer_start; i != send_array->buffer_end; ++i) {\n        if (length == 0)\n            break;\n\n        uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE;\n\n        if (n == data[0]) {\n            if (send_array->buffer[num]) {\n                uint64_t sent_time = send_array->buffer[num]->sent_time;\n\n                if ((sent_time + rtt_time) < temp_time) {\n                    send_array->buffer[num]->sent_time = 0;\n                }\n            }\n\n            ++data;\n            --length;\n            n = 0;\n            ++requested;\n        } else {\n            if (send_array->buffer[num]) {\n                uint64_t sent_time = send_array->buffer[num]->sent_time;\n\n                if (l_sent_time < sent_time)\n                    l_sent_time = sent_time;\n\n                free(send_array->buffer[num]);\n                send_array->buffer[num] = NULL;\n            }\n        }\n\n        if (n == 255) {\n            n = 1;\n\n            if (data[0] != 0)\n                return -1;\n\n            ++data;\n            --length;\n        } else {\n            ++n;\n        }\n    }\n\n    if (*latest_send_time < l_sent_time)\n        *latest_send_time = l_sent_time;\n\n    return requested;\n}\n\n/** END: Array Related functions **/\n\n#define MAX_DATA_DATA_PACKET_SIZE (MAX_CRYPTO_PACKET_SIZE - (1 + sizeof(uint16_t) + crypto_box_MACBYTES))\n\n/* Creates and sends a data packet to the peer using the fastest route.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length)\n{\n    if (length == 0 || length + (1 + sizeof(uint16_t) + crypto_box_MACBYTES) > MAX_CRYPTO_PACKET_SIZE)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    pthread_mutex_lock(&conn->mutex);\n    uint8_t packet[1 + sizeof(uint16_t) + length + crypto_box_MACBYTES];\n    packet[0] = NET_PACKET_CRYPTO_DATA;\n    memcpy(packet + 1, conn->sent_nonce + (crypto_box_NONCEBYTES - sizeof(uint16_t)), sizeof(uint16_t));\n    int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t));\n\n    if (len + 1 + sizeof(uint16_t) != sizeof(packet)) {\n        pthread_mutex_unlock(&conn->mutex);\n        return -1;\n    }\n\n    increment_nonce(conn->sent_nonce);\n    pthread_mutex_unlock(&conn->mutex);\n\n    return send_packet_to(c, crypt_connection_id, packet, sizeof(packet));\n}\n\n/* Creates and sends a data packet with buffer_start and num to the peer using the fastest route.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num,\n                                   const uint8_t *data, uint16_t length)\n{\n    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE)\n        return -1;\n\n    num = htonl(num);\n    buffer_start = htonl(buffer_start);\n    uint16_t padding_length = (MAX_CRYPTO_DATA_SIZE - length) % CRYPTO_MAX_PADDING;\n    uint8_t packet[sizeof(uint32_t) + sizeof(uint32_t) + padding_length + length];\n    memcpy(packet, &buffer_start, sizeof(uint32_t));\n    memcpy(packet + sizeof(uint32_t), &num, sizeof(uint32_t));\n    memset(packet + (sizeof(uint32_t) * 2), PACKET_ID_PADDING, padding_length);\n    memcpy(packet + (sizeof(uint32_t) * 2) + padding_length, data, length);\n\n    return send_data_packet(c, crypt_connection_id, packet, sizeof(packet));\n}\n\nstatic int reset_max_speed_reached(Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    /* If last packet send failed, try to send packet again.\n       If sending it fails we won't be able to send the new packet. */\n    if (conn->maximum_speed_reached) {\n        Packet_Data *dt = NULL;\n        uint32_t packet_num = conn->send_array.buffer_end - 1;\n        int ret = get_data_pointer(&conn->send_array, &dt, packet_num);\n\n        uint8_t send_failed = 0;\n\n        if (ret == 1) {\n            if (!dt->sent_time) {\n                if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data,\n                                            dt->length) != 0) {\n                    send_failed = 1;\n                } else {\n                    dt->sent_time = current_time_monotonic();\n                }\n            }\n        }\n\n        if (!send_failed) {\n            conn->maximum_speed_reached = 0;\n        } else {\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n/*  return -1 if data could not be put in packet queue.\n *  return positive packet number if data was put into the queue.\n */\nstatic int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length,\n                                    uint8_t congestion_control)\n{\n    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    /* If last packet send failed, try to send packet again.\n       If sending it fails we won't be able to send the new packet. */\n    reset_max_speed_reached(c, crypt_connection_id);\n\n    if (conn->maximum_speed_reached && congestion_control) {\n        return -1;\n    }\n\n    Packet_Data dt;\n    dt.sent_time = 0;\n    dt.length = length;\n    memcpy(dt.data, data, length);\n    pthread_mutex_lock(&conn->mutex);\n    int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt);\n    pthread_mutex_unlock(&conn->mutex);\n\n    if (packet_num == -1)\n        return -1;\n\n    if (!congestion_control && conn->maximum_speed_reached) {\n        return packet_num;\n    }\n\n    if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, data, length) == 0) {\n        Packet_Data *dt1 = NULL;\n\n        if (get_data_pointer(&conn->send_array, &dt1, packet_num) == 1)\n            dt1->sent_time = current_time_monotonic();\n    } else {\n        conn->maximum_speed_reached = 1;\n        LOGGER_ERROR(\"send_data_packet failed\\n\");\n    }\n\n    return packet_num;\n}\n\n/* Get the lowest 2 bytes from the nonce and convert\n * them to host byte format before returning them.\n */\nstatic uint16_t get_nonce_uint16(const uint8_t *nonce)\n{\n    uint16_t num;\n    memcpy(&num, nonce + (crypto_box_NONCEBYTES - sizeof(uint16_t)), sizeof(uint16_t));\n    return ntohs(num);\n}\n\n#define DATA_NUM_THRESHOLD 21845\n\n/* Handle a data packet.\n * Decrypt packet of length and put it into data.\n * data must be at least MAX_DATA_DATA_PACKET_SIZE big.\n *\n * return -1 on failure.\n * return length of data on success.\n */\nstatic int handle_data_packet(const Net_Crypto *c, int crypt_connection_id, uint8_t *data, const uint8_t *packet,\n                              uint16_t length)\n{\n    if (length <= (1 + sizeof(uint16_t) + crypto_box_MACBYTES) || length > MAX_CRYPTO_PACKET_SIZE)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    memcpy(nonce, conn->recv_nonce, crypto_box_NONCEBYTES);\n    uint16_t num_cur_nonce = get_nonce_uint16(nonce);\n    uint16_t num;\n    memcpy(&num, packet + 1, sizeof(uint16_t));\n    num = ntohs(num);\n    uint16_t diff = num - num_cur_nonce;\n    increment_nonce_number(nonce, diff);\n    int len = decrypt_data_symmetric(conn->shared_key, nonce, packet + 1 + sizeof(uint16_t),\n                                     length - (1 + sizeof(uint16_t)), data);\n\n    if ((unsigned int)len != length - (1 + sizeof(uint16_t) + crypto_box_MACBYTES))\n        return -1;\n\n    if (diff > DATA_NUM_THRESHOLD * 2) {\n        increment_nonce_number(conn->recv_nonce, DATA_NUM_THRESHOLD);\n    }\n\n    return len;\n}\n\n/* Send a request packet.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_request_packet(Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint8_t data[MAX_CRYPTO_DATA_SIZE];\n    int len = generate_request_packet(data, sizeof(data), &conn->recv_array);\n\n    if (len == -1)\n        return -1;\n\n    return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, data,\n                                   len);\n}\n\n/* Send up to max num previously requested data packets.\n *\n * return -1 on failure.\n * return number of packets sent on success.\n */\nstatic int send_requested_packets(Net_Crypto *c, int crypt_connection_id, uint32_t max_num)\n{\n    if (max_num == 0)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint64_t temp_time = current_time_monotonic();\n    uint32_t i, num_sent = 0, array_size = num_packets_array(&conn->send_array);\n\n    for (i = 0; i < array_size; ++i) {\n        Packet_Data *dt;\n        uint32_t packet_num = (i + conn->send_array.buffer_start);\n        int ret = get_data_pointer(&conn->send_array, &dt, packet_num);\n\n        if (ret == -1) {\n            return -1;\n        } else if (ret == 0) {\n            continue;\n        }\n\n        if (dt->sent_time) {\n            continue;\n        }\n\n        if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data,\n                                    dt->length) == 0) {\n            dt->sent_time = temp_time;\n            ++num_sent;\n        }\n\n        if (num_sent >= max_num)\n            break;\n    }\n\n    return num_sent;\n}\n\n\n/* Add a new temp packet to send repeatedly.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int new_temp_packet(const Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length)\n{\n    if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint8_t *temp_packet = malloc(length);\n\n    if (temp_packet == 0)\n        return -1;\n\n    if (conn->temp_packet)\n        free(conn->temp_packet);\n\n    memcpy(temp_packet, packet, length);\n    conn->temp_packet = temp_packet;\n    conn->temp_packet_length = length;\n    conn->temp_packet_sent_time = 0;\n    conn->temp_packet_num_sent = 0;\n    return 0;\n}\n\n/* Clear the temp packet.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int clear_temp_packet(const Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    if (conn->temp_packet)\n        free(conn->temp_packet);\n\n    conn->temp_packet = 0;\n    conn->temp_packet_length = 0;\n    conn->temp_packet_sent_time = 0;\n    conn->temp_packet_num_sent = 0;\n    return 0;\n}\n\n\n/* Send the temp packet.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_temp_packet(Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    if (!conn->temp_packet)\n        return -1;\n\n    if (send_packet_to(c, crypt_connection_id, conn->temp_packet, conn->temp_packet_length) != 0)\n        return -1;\n\n    conn->temp_packet_sent_time = current_time_monotonic();\n    ++conn->temp_packet_num_sent;\n    return 0;\n}\n\n/* Create a handshake packet and set it as a temp packet.\n * cookie must be COOKIE_LENGTH.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int create_send_handshake(Net_Crypto *c, int crypt_connection_id, const uint8_t *cookie,\n                                 const uint8_t *dht_public_key)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint8_t handshake_packet[HANDSHAKE_PACKET_LENGTH];\n\n    if (create_crypto_handshake(c, handshake_packet, cookie, conn->sent_nonce, conn->sessionpublic_key,\n                                conn->public_key, dht_public_key) != sizeof(handshake_packet))\n        return -1;\n\n    if (new_temp_packet(c, crypt_connection_id, handshake_packet, sizeof(handshake_packet)) != 0)\n        return -1;\n\n    send_temp_packet(c, crypt_connection_id);\n    return 0;\n}\n\n/* Send a kill packet.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_kill_packet(Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint8_t kill_packet = PACKET_ID_KILL;\n    return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end,\n                                   &kill_packet, sizeof(kill_packet));\n}\n\nstatic void connection_kill(Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return;\n\n    if (conn->connection_status_callback) {\n        conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0);\n    }\n\n    crypto_kill(c, crypt_connection_id);\n}\n\n/* Handle a received data packet.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int handle_data_packet_helper(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length,\n                                     _Bool udp)\n{\n    if (length > MAX_CRYPTO_PACKET_SIZE || length <= CRYPTO_DATA_PACKET_MIN_SIZE)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint8_t data[MAX_DATA_DATA_PACKET_SIZE];\n    int len = handle_data_packet(c, crypt_connection_id, data, packet, length);\n\n    if (len <= (int)(sizeof(uint32_t) * 2))\n        return -1;\n\n    uint32_t buffer_start, num;\n    memcpy(&buffer_start, data, sizeof(uint32_t));\n    memcpy(&num, data + sizeof(uint32_t), sizeof(uint32_t));\n    buffer_start = ntohl(buffer_start);\n    num = ntohl(num);\n\n    uint64_t rtt_calc_time = 0;\n\n    if (buffer_start != conn->send_array.buffer_start) {\n        Packet_Data *packet_time;\n\n        if (get_data_pointer(&conn->send_array, &packet_time, conn->send_array.buffer_start) == 1) {\n            rtt_calc_time = packet_time->sent_time;\n        }\n\n        if (clear_buffer_until(&conn->send_array, buffer_start) != 0) {\n            return -1;\n        }\n    }\n\n    uint8_t *real_data = data + (sizeof(uint32_t) * 2);\n    uint16_t real_length = len - (sizeof(uint32_t) * 2);\n\n    while (real_data[0] == PACKET_ID_PADDING) { /* Remove Padding */\n        ++real_data;\n        --real_length;\n\n        if (real_length == 0)\n            return -1;\n    }\n\n    if (real_data[0] == PACKET_ID_KILL) {\n        connection_kill(c, crypt_connection_id);\n        return 0;\n    }\n\n    if (conn->status == CRYPTO_CONN_NOT_CONFIRMED) {\n        clear_temp_packet(c, crypt_connection_id);\n        conn->status = CRYPTO_CONN_ESTABLISHED;\n\n        if (conn->connection_status_callback)\n            conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 1);\n    }\n\n    if (real_data[0] == PACKET_ID_REQUEST) {\n        uint64_t rtt_time;\n\n        if (udp) {\n            rtt_time = conn->rtt_time;\n        } else {\n            rtt_time = DEFAULT_TCP_PING_CONNECTION;\n        }\n\n        int requested = handle_request_packet(&conn->send_array, real_data, real_length, &rtt_calc_time, rtt_time);\n\n        if (requested == -1) {\n            return -1;\n        } else {\n            //TODO?\n        }\n\n        set_buffer_end(&conn->recv_array, num);\n    } else if (real_data[0] >= CRYPTO_RESERVED_PACKETS && real_data[0] < PACKET_ID_LOSSY_RANGE_START) {\n        Packet_Data dt;\n        dt.length = real_length;\n        memcpy(dt.data, real_data, real_length);\n\n        if (add_data_to_buffer(&conn->recv_array, num, &dt) != 0)\n            return -1;\n\n\n        while (1) {\n            pthread_mutex_lock(&conn->mutex);\n            int ret = read_data_beg_buffer(&conn->recv_array, &dt);\n            pthread_mutex_unlock(&conn->mutex);\n\n            if (ret == -1)\n                break;\n\n            if (conn->connection_data_callback)\n                conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, dt.data,\n                                               dt.length);\n\n            /* conn might get killed in callback. */\n            conn = get_crypto_connection(c, crypt_connection_id);\n\n            if (conn == 0)\n                return -1;\n        }\n\n        /* Packet counter. */\n        ++conn->packet_counter;\n    } else if (real_data[0] >= PACKET_ID_LOSSY_RANGE_START &&\n               real_data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) {\n\n        set_buffer_end(&conn->recv_array, num);\n\n        if (conn->connection_lossy_data_callback)\n            conn->connection_lossy_data_callback(conn->connection_lossy_data_callback_object,\n                                                 conn->connection_lossy_data_callback_id, real_data, real_length);\n\n    } else {\n        return -1;\n    }\n\n    if (rtt_calc_time != 0) {\n        uint64_t rtt_time = current_time_monotonic() - rtt_calc_time;\n\n        if (rtt_time < conn->rtt_time)\n            conn->rtt_time = rtt_time;\n    }\n\n    return 0;\n}\n\n/* Handle a packet that was received for the connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length,\n                                    _Bool udp)\n{\n    if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    switch (packet[0]) {\n        case NET_PACKET_COOKIE_RESPONSE: {\n            if (conn->status != CRYPTO_CONN_COOKIE_REQUESTING)\n                return -1;\n\n            uint8_t cookie[COOKIE_LENGTH];\n            uint64_t number;\n\n            if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key) != sizeof(cookie))\n                return -1;\n\n            if (number != conn->cookie_request_number)\n                return -1;\n\n            if (create_send_handshake(c, crypt_connection_id, cookie, conn->dht_public_key) != 0)\n                return -1;\n\n            conn->status = CRYPTO_CONN_HANDSHAKE_SENT;\n            return 0;\n        }\n\n        case NET_PACKET_CRYPTO_HS: {\n            if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT\n                    || conn->status == CRYPTO_CONN_NOT_CONFIRMED) {\n                uint8_t peer_real_pk[crypto_box_PUBLICKEYBYTES];\n                uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];\n                uint8_t cookie[COOKIE_LENGTH];\n\n                if (handle_crypto_handshake(c, conn->recv_nonce, conn->peersessionpublic_key, peer_real_pk, dht_public_key, cookie,\n                                            packet, length, conn->public_key) != 0)\n                    return -1;\n\n                if (public_key_cmp(dht_public_key, conn->dht_public_key) == 0) {\n                    encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);\n\n                    if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) {\n                        if (create_send_handshake(c, crypt_connection_id, cookie, dht_public_key) != 0)\n                            return -1;\n                    }\n\n                    conn->status = CRYPTO_CONN_NOT_CONFIRMED;\n                } else {\n                    if (conn->dht_pk_callback)\n                        conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key);\n                }\n\n            } else {\n                return -1;\n            }\n\n            return 0;\n        }\n\n        case NET_PACKET_CRYPTO_DATA: {\n            if (conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) {\n                return handle_data_packet_helper(c, crypt_connection_id, packet, length, udp);\n            } else {\n                return -1;\n            }\n\n            return 0;\n        }\n\n        default: {\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n/* Set the size of the friend list to numfriends.\n *\n *  return -1 if realloc fails.\n *  return 0 if it succeeds.\n */\nstatic int realloc_cryptoconnection(Net_Crypto *c, uint32_t num)\n{\n    if (num == 0) {\n        free(c->crypto_connections);\n        c->crypto_connections = NULL;\n        return 0;\n    }\n\n    Crypto_Connection *newcrypto_connections = realloc(c->crypto_connections, num * sizeof(Crypto_Connection));\n\n    if (newcrypto_connections == NULL)\n        return -1;\n\n    c->crypto_connections = newcrypto_connections;\n    return 0;\n}\n\n\n/* Create a new empty crypto connection.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nstatic int create_crypto_connection(Net_Crypto *c)\n{\n    uint32_t i;\n\n    for (i = 0; i < c->crypto_connections_length; ++i) {\n        if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION)\n            return i;\n    }\n\n    while (1) { /* TODO: is this really the best way to do this? */\n        pthread_mutex_lock(&c->connections_mutex);\n\n        if (!c->connection_use_counter) {\n            break;\n        }\n\n        pthread_mutex_unlock(&c->connections_mutex);\n    }\n\n    int id = -1;\n\n    if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) {\n        id = c->crypto_connections_length;\n        ++c->crypto_connections_length;\n        memset(&(c->crypto_connections[id]), 0, sizeof(Crypto_Connection));\n\n        if (pthread_mutex_init(&c->crypto_connections[id].mutex, NULL) != 0) {\n            pthread_mutex_unlock(&c->connections_mutex);\n            return -1;\n        }\n    }\n\n    pthread_mutex_unlock(&c->connections_mutex);\n    return id;\n}\n\n/* Wipe a crypto connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id)\n{\n    if (crypt_connection_id_not_valid(c, crypt_connection_id))\n        return -1;\n\n    uint32_t i;\n\n    /* Keep mutex, only destroy it when connection is realloced out. */\n    pthread_mutex_t mutex = c->crypto_connections[crypt_connection_id].mutex;\n    sodium_memzero(&(c->crypto_connections[crypt_connection_id]), sizeof(Crypto_Connection));\n    c->crypto_connections[crypt_connection_id].mutex = mutex;\n\n    for (i = c->crypto_connections_length; i != 0; --i) {\n        if (c->crypto_connections[i - 1].status == CRYPTO_CONN_NO_CONNECTION) {\n            pthread_mutex_destroy(&c->crypto_connections[i - 1].mutex);\n        } else {\n            break;\n        }\n    }\n\n    if (c->crypto_connections_length != i) {\n        c->crypto_connections_length = i;\n        realloc_cryptoconnection(c, c->crypto_connections_length);\n    }\n\n    return 0;\n}\n\n/* Get crypto connection id from public key of peer.\n *\n *  return -1 if there are no connections like we are looking for.\n *  return id if it found it.\n */\nstatic int getcryptconnection_id(const Net_Crypto *c, const uint8_t *public_key)\n{\n    uint32_t i;\n\n    for (i = 0; i < c->crypto_connections_length; ++i) {\n        if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION)\n            if (public_key_cmp(public_key, c->crypto_connections[i].public_key) == 0)\n                return i;\n    }\n\n    return -1;\n}\n\n/* Add a source to the crypto connection.\n * This is to be used only when we have received a packet from that source.\n *\n *  return -1 on failure.\n *  return positive number on success.\n *  0 if source was a direct UDP connection.\n */\nstatic int crypto_connection_add_source(Net_Crypto *c, int crypt_connection_id, IP_Port source)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    if (source.ip.family == AF_INET || source.ip.family == AF_INET6) {\n        if (add_ip_port_connection(c, crypt_connection_id, source) != 0)\n            return -1;\n\n        if (source.ip.family == AF_INET) {\n            conn->direct_lastrecv_timev4 = unix_time();\n        } else {\n            conn->direct_lastrecv_timev6 = unix_time();\n        }\n\n        return 0;\n    } else if (source.ip.family == TCP_FAMILY) {\n        if (add_tcp_number_relay_connection(c->tcp_c, conn->connection_number_tcp, source.ip.ip6.uint32[0]) == 0)\n            return 1;\n    }\n\n    return -1;\n}\n\n\n/* Set function to be called when someone requests a new connection to us.\n *\n * The set function should return -1 on failure and 0 on success.\n *\n * n_c is only valid for the duration of the function call.\n */\nvoid new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c),\n                            void *object)\n{\n    c->new_connection_callback = new_connection_callback;\n    c->new_connection_callback_object = object;\n}\n\n/* Handle a handshake packet by someone who wants to initiate a new connection with us.\n * This calls the callback set by new_connection_handler() if the handshake is ok.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, const uint8_t *data, uint16_t length)\n{\n    New_Connection n_c;\n    n_c.cookie = malloc(COOKIE_LENGTH);\n\n    if (n_c.cookie == NULL)\n        return -1;\n\n    n_c.source = source;\n    n_c.cookie_length = COOKIE_LENGTH;\n\n    if (handle_crypto_handshake(c, n_c.recv_nonce, n_c.peersessionpublic_key, n_c.public_key, n_c.dht_public_key,\n                                n_c.cookie, data, length, 0) != 0) {\n        free(n_c.cookie);\n        return -1;\n    }\n\n    int crypt_connection_id = getcryptconnection_id(c, n_c.public_key);\n\n    if (crypt_connection_id != -1) {\n        Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n        if (public_key_cmp(n_c.dht_public_key, conn->dht_public_key) != 0) {\n            connection_kill(c, crypt_connection_id);\n        } else {\n            int ret = -1;\n\n            if (conn && (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT)) {\n                memcpy(conn->recv_nonce, n_c.recv_nonce, crypto_box_NONCEBYTES);\n                memcpy(conn->peersessionpublic_key, n_c.peersessionpublic_key, crypto_box_PUBLICKEYBYTES);\n                encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);\n\n                crypto_connection_add_source(c, crypt_connection_id, source);\n\n                if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) {\n                    conn->status = CRYPTO_CONN_NOT_CONFIRMED;\n                    ret = 0;\n                }\n            }\n\n            free(n_c.cookie);\n            return ret;\n        }\n    }\n\n    int ret = c->new_connection_callback(c->new_connection_callback_object, &n_c);\n    free(n_c.cookie);\n    return ret;\n}\n\n/* Accept a crypto connection.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nint accept_crypto_connection(Net_Crypto *c, New_Connection *n_c)\n{\n    if (getcryptconnection_id(c, n_c->public_key) != -1)\n        return -1;\n\n    int crypt_connection_id = create_crypto_connection(c);\n\n    if (crypt_connection_id == -1)\n        return -1;\n\n    Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id];\n\n    if (n_c->cookie_length != COOKIE_LENGTH)\n        return -1;\n\n    pthread_mutex_lock(&c->tcp_mutex);\n    int connection_number_tcp = new_tcp_connection_to(c->tcp_c, n_c->dht_public_key, crypt_connection_id);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    if (connection_number_tcp == -1)\n        return -1;\n\n    conn->connection_number_tcp = connection_number_tcp;\n    memcpy(conn->public_key, n_c->public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(conn->recv_nonce, n_c->recv_nonce, crypto_box_NONCEBYTES);\n    memcpy(conn->peersessionpublic_key, n_c->peersessionpublic_key, crypto_box_PUBLICKEYBYTES);\n    random_nonce(conn->sent_nonce);\n    crypto_box_keypair(conn->sessionpublic_key, conn->sessionsecret_key);\n    encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);\n    conn->status = CRYPTO_CONN_NOT_CONFIRMED;\n\n    if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0) {\n        pthread_mutex_lock(&c->tcp_mutex);\n        kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp);\n        pthread_mutex_unlock(&c->tcp_mutex);\n        conn->status = CRYPTO_CONN_NO_CONNECTION;\n        return -1;\n    }\n\n    memcpy(conn->dht_public_key, n_c->dht_public_key, crypto_box_PUBLICKEYBYTES);\n    conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;\n    conn->packet_send_rate_requested = CRYPTO_PACKET_MIN_RATE;\n    conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH;\n    conn->rtt_time = DEFAULT_PING_CONNECTION;\n    crypto_connection_add_source(c, crypt_connection_id, n_c->source);\n    return crypt_connection_id;\n}\n\n/* Create a crypto connection.\n * If one to that real public key already exists, return it.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nint new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key)\n{\n    int crypt_connection_id = getcryptconnection_id(c, real_public_key);\n\n    if (crypt_connection_id != -1)\n        return crypt_connection_id;\n\n    crypt_connection_id = create_crypto_connection(c);\n\n    if (crypt_connection_id == -1)\n        return -1;\n\n    Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id];\n\n    if (conn == 0)\n        return -1;\n\n    pthread_mutex_lock(&c->tcp_mutex);\n    int connection_number_tcp = new_tcp_connection_to(c->tcp_c, dht_public_key, crypt_connection_id);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    if (connection_number_tcp == -1)\n        return -1;\n\n    conn->connection_number_tcp = connection_number_tcp;\n    memcpy(conn->public_key, real_public_key, crypto_box_PUBLICKEYBYTES);\n    random_nonce(conn->sent_nonce);\n    crypto_box_keypair(conn->sessionpublic_key, conn->sessionsecret_key);\n    conn->status = CRYPTO_CONN_COOKIE_REQUESTING;\n    conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;\n    conn->packet_send_rate_requested = CRYPTO_PACKET_MIN_RATE;\n    conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH;\n    conn->rtt_time = DEFAULT_PING_CONNECTION;\n    memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES);\n\n    conn->cookie_request_number = random_64b();\n    uint8_t cookie_request[COOKIE_REQUEST_LENGTH];\n\n    if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number,\n                              conn->shared_key) != sizeof(cookie_request)\n            || new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0) {\n        pthread_mutex_lock(&c->tcp_mutex);\n        kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp);\n        pthread_mutex_unlock(&c->tcp_mutex);\n        conn->status = CRYPTO_CONN_NO_CONNECTION;\n        return -1;\n    }\n\n    return crypt_connection_id;\n}\n\n/* Set the direct ip of the crypto connection.\n *\n * Connected is 0 if we are not sure we are connected to that person, 1 if we are sure.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, _Bool connected)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    if (add_ip_port_connection(c, crypt_connection_id, ip_port) == 0) {\n        if (connected) {\n            if (ip_port.ip.family == AF_INET) {\n                conn->direct_lastrecv_timev4 = unix_time();\n            } else {\n                conn->direct_lastrecv_timev6 = unix_time();\n            }\n        } else {\n            if (ip_port.ip.family == AF_INET) {\n                conn->direct_lastrecv_timev4 = 0;\n            } else {\n                conn->direct_lastrecv_timev6 = 0;\n            }\n        }\n\n        return 0;\n    }\n\n    return -1;\n}\n\n\nstatic int tcp_data_callback(void *object, int id, const uint8_t *data, uint16_t length)\n{\n    if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE)\n        return -1;\n\n    Net_Crypto *c = object;\n\n    Crypto_Connection *conn = get_crypto_connection(c, id);\n\n    if (conn == 0)\n        return -1;\n\n    if (data[0] == NET_PACKET_COOKIE_REQUEST) {\n        return tcp_handle_cookie_request(c, conn->connection_number_tcp, data, length);\n    }\n\n    pthread_mutex_unlock(&c->tcp_mutex);\n    int ret = handle_packet_connection(c, id, data, length, 0);\n    pthread_mutex_lock(&c->tcp_mutex);\n\n    if (ret != 0)\n        return -1;\n\n    //TODO detect and kill bad TCP connections.\n    return 0;\n}\n\nstatic int tcp_oob_callback(void *object, const uint8_t *public_key, unsigned int tcp_connections_number,\n                            const uint8_t *data, uint16_t length)\n{\n    if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE)\n        return -1;\n\n    Net_Crypto *c = object;\n\n    if (data[0] == NET_PACKET_COOKIE_REQUEST) {\n        return tcp_oob_handle_cookie_request(c, tcp_connections_number, public_key, data, length);\n    } else if (data[0] == NET_PACKET_CRYPTO_HS) {\n        IP_Port source;\n        source.port = 0;\n        source.ip.family = TCP_FAMILY;\n        source.ip.ip6.uint32[0] = tcp_connections_number;\n\n        if (handle_new_connection_handshake(c, source, data, length) != 0)\n            return -1;\n\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n/* Add a tcp relay, associating it to a crypt_connection_id.\n *\n * return 0 if it was added.\n * return -1 if it wasn't.\n */\nint add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, const uint8_t *public_key)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    pthread_mutex_lock(&c->tcp_mutex);\n    int ret = add_tcp_relay_connection(c->tcp_c, conn->connection_number_tcp, ip_port, public_key);\n    pthread_mutex_unlock(&c->tcp_mutex);\n    return ret;\n}\n\n/* Add a tcp relay to the array.\n *\n * return 0 if it was added.\n * return -1 if it wasn't.\n */\nint add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key)\n{\n    pthread_mutex_lock(&c->tcp_mutex);\n    int ret = add_tcp_relay_global(c->tcp_c, ip_port, public_key);\n    pthread_mutex_unlock(&c->tcp_mutex);\n    return ret;\n}\n\n/* Return a random TCP connection number for use in send_tcp_onion_request.\n *\n * TODO: This number is just the index of an array that the elements can\n * change without warning.\n *\n * return TCP connection number on success.\n * return -1 on failure.\n */\nint get_random_tcp_con_number(Net_Crypto *c)\n{\n    pthread_mutex_lock(&c->tcp_mutex);\n    int ret = get_random_tcp_onion_conn_number(c->tcp_c);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    return ret;\n}\n\n/* Send an onion packet via the TCP relay corresponding to tcp_connections_number.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint send_tcp_onion_request(Net_Crypto *c, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length)\n{\n    pthread_mutex_lock(&c->tcp_mutex);\n    int ret = tcp_send_onion_request(c->tcp_c, tcp_connections_number, data, length);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    return ret;\n}\n\n/* Copy a maximum of num TCP relays we are connected to to tcp_relays.\n * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.\n *\n * return number of relays copied to tcp_relays on success.\n * return 0 on failure.\n */\nunsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num)\n{\n    if (num == 0)\n        return 0;\n\n    pthread_mutex_lock(&c->tcp_mutex);\n    unsigned int ret = tcp_copy_connected_relays(c->tcp_c, tcp_relays, num);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    return ret;\n}\n\nstatic void do_tcp(Net_Crypto *c)\n{\n    pthread_mutex_lock(&c->tcp_mutex);\n    do_tcp_connections(c->tcp_c);\n    pthread_mutex_unlock(&c->tcp_mutex);\n\n    uint32_t i;\n\n    for (i = 0; i < c->crypto_connections_length; ++i) {\n        Crypto_Connection *conn = get_crypto_connection(c, i);\n\n        if (conn == 0)\n            return;\n\n        if (conn->status == CRYPTO_CONN_ESTABLISHED) {\n            _Bool direct_connected = 0;\n            crypto_connection_status(c, i, &direct_connected, NULL);\n\n            if (direct_connected) {\n                pthread_mutex_lock(&c->tcp_mutex);\n                set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 0);\n                pthread_mutex_unlock(&c->tcp_mutex);\n            } else {\n                pthread_mutex_lock(&c->tcp_mutex);\n                set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 1);\n                pthread_mutex_unlock(&c->tcp_mutex);\n            }\n        }\n    }\n}\n\n/* Set function to be called when connection with crypt_connection_id goes connects/disconnects.\n *\n * The set function should return -1 on failure and 0 on success.\n * Note that if this function is set, the connection will clear itself on disconnect.\n * Object and id will be passed to this function untouched.\n * status is 1 if the connection is going online, 0 if it is going offline.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint connection_status_handler(const Net_Crypto *c, int crypt_connection_id,\n                              int (*connection_status_callback)(void *object, int id, uint8_t status), void *object, int id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    conn->connection_status_callback = connection_status_callback;\n    conn->connection_status_callback_object = object;\n    conn->connection_status_callback_id = id;\n    return 0;\n}\n\n/* Set function to be called when connection with crypt_connection_id receives a data packet of length.\n *\n * The set function should return -1 on failure and 0 on success.\n * Object and id will be passed to this function untouched.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint connection_data_handler(const Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object,\n                            int id, uint8_t *data, uint16_t length), void *object, int id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    conn->connection_data_callback = connection_data_callback;\n    conn->connection_data_callback_object = object;\n    conn->connection_data_callback_id = id;\n    return 0;\n}\n\n/* Set function to be called when connection with crypt_connection_id receives a lossy data packet of length.\n *\n * The set function should return -1 on failure and 0 on success.\n * Object and id will be passed to this function untouched.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id,\n                                  int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object, int id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    conn->connection_lossy_data_callback = connection_lossy_data_callback;\n    conn->connection_lossy_data_callback_object = object;\n    conn->connection_lossy_data_callback_id = id;\n    return 0;\n}\n\n\n/* Set the function for this friend that will be callbacked with object and number if\n * the friend sends us a different dht public key than we have associated to him.\n *\n * If this function is called, the connection should be recreated with the new public key.\n *\n * object and number will be passed as argument to this function.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number,\n                       const uint8_t *dht_public_key), void *object, uint32_t number)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    conn->dht_pk_callback = function;\n    conn->dht_pk_callback_object = object;\n    conn->dht_pk_callback_number = number;\n    return 0;\n}\n\n/* Get the crypto connection id from the ip_port.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nstatic int crypto_id_ip_port(const Net_Crypto *c, IP_Port ip_port)\n{\n    return bs_list_find(&c->ip_port_list, (uint8_t *)&ip_port);\n}\n\n#define CRYPTO_MIN_PACKET_SIZE (1 + sizeof(uint16_t) + crypto_box_MACBYTES)\n\n/* Handle raw UDP packets coming directly from the socket.\n *\n * Handles:\n * Cookie response packets.\n * Crypto handshake packets.\n * Crypto data packets.\n *\n */\nstatic int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    if (length <= CRYPTO_MIN_PACKET_SIZE || length > MAX_CRYPTO_PACKET_SIZE)\n        return 1;\n\n    Net_Crypto *c = object;\n    int crypt_connection_id = crypto_id_ip_port(c, source);\n\n    if (crypt_connection_id == -1) {\n        if (packet[0] != NET_PACKET_CRYPTO_HS)\n            return 1;\n\n        if (handle_new_connection_handshake(c, source, packet, length) != 0)\n            return 1;\n\n        return 0;\n    }\n\n    if (handle_packet_connection(c, crypt_connection_id, packet, length, 1) != 0)\n        return 1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    pthread_mutex_lock(&conn->mutex);\n\n    if (source.ip.family == AF_INET) {\n        conn->direct_lastrecv_timev4 = unix_time();\n    } else {\n        conn->direct_lastrecv_timev6 = unix_time();\n    }\n\n    pthread_mutex_unlock(&conn->mutex);\n    return 0;\n}\n\n/* The dT for the average packet receiving rate calculations.\n   Also used as the */\n#define PACKET_COUNTER_AVERAGE_INTERVAL 50\n\n/* Ratio of recv queue size / recv packet rate (in seconds) times\n * the number of ms between request packets to send at that ratio\n */\n#define REQUEST_PACKETS_COMPARE_CONSTANT (0.125 * 100.0)\n\n/* Timeout for increasing speed after congestion event (in ms). */\n#define CONGESTION_EVENT_TIMEOUT 1000\n\n/* If the send queue is SEND_QUEUE_RATIO times larger than the\n * calculated link speed the packet send speed will be reduced\n * by a value depending on this number.\n */\n#define SEND_QUEUE_RATIO 2.0\n\nstatic void send_crypto_packets(Net_Crypto *c)\n{\n    uint32_t i;\n    uint64_t temp_time = current_time_monotonic();\n    double total_send_rate = 0;\n    uint32_t peak_request_packet_interval = ~0;\n\n    for (i = 0; i < c->crypto_connections_length; ++i) {\n        Crypto_Connection *conn = get_crypto_connection(c, i);\n\n        if (conn == 0)\n            return;\n\n        if (CRYPTO_SEND_PACKET_INTERVAL + conn->temp_packet_sent_time < temp_time) {\n            send_temp_packet(c, i);\n        }\n\n        if ((conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED)\n                && ((CRYPTO_SEND_PACKET_INTERVAL) + conn->last_request_packet_sent) < temp_time) {\n            if (send_request_packet(c, i) == 0) {\n                conn->last_request_packet_sent = temp_time;\n            }\n\n        }\n\n        if (conn->status == CRYPTO_CONN_ESTABLISHED) {\n            if (conn->packet_recv_rate > CRYPTO_PACKET_MIN_RATE) {\n                double request_packet_interval = (REQUEST_PACKETS_COMPARE_CONSTANT / (((double)num_packets_array(\n                                                      &conn->recv_array) + 1.0) / (conn->packet_recv_rate + 1.0)));\n\n                double request_packet_interval2 = ((CRYPTO_PACKET_MIN_RATE / conn->packet_recv_rate) *\n                                                   (double)CRYPTO_SEND_PACKET_INTERVAL) + (double)PACKET_COUNTER_AVERAGE_INTERVAL;\n\n                if (request_packet_interval2 < request_packet_interval)\n                    request_packet_interval = request_packet_interval2;\n\n                if (request_packet_interval < PACKET_COUNTER_AVERAGE_INTERVAL)\n                    request_packet_interval = PACKET_COUNTER_AVERAGE_INTERVAL;\n\n                if (request_packet_interval > CRYPTO_SEND_PACKET_INTERVAL)\n                    request_packet_interval = CRYPTO_SEND_PACKET_INTERVAL;\n\n                if (temp_time - conn->last_request_packet_sent > (uint64_t)request_packet_interval) {\n                    if (send_request_packet(c, i) == 0) {\n                        conn->last_request_packet_sent = temp_time;\n                    }\n                }\n\n                if (request_packet_interval < peak_request_packet_interval) {\n                    peak_request_packet_interval = request_packet_interval;\n                }\n            }\n\n            if ((PACKET_COUNTER_AVERAGE_INTERVAL + conn->packet_counter_set) < temp_time) {\n\n                double dt = temp_time - conn->packet_counter_set;\n\n                conn->packet_recv_rate = (double)conn->packet_counter / (dt / 1000.0);\n                conn->packet_counter = 0;\n                conn->packet_counter_set = temp_time;\n\n                uint32_t packets_sent = conn->packets_sent;\n                conn->packets_sent = 0;\n\n                uint32_t packets_resent = conn->packets_resent;\n                conn->packets_resent = 0;\n\n                /* conjestion control\n                    calculate a new value of conn->packet_send_rate based on some data\n                 */\n\n                unsigned int pos = conn->last_sendqueue_counter % CONGESTION_QUEUE_ARRAY_SIZE;\n                conn->last_sendqueue_size[pos] = num_packets_array(&conn->send_array);\n                ++conn->last_sendqueue_counter;\n\n                unsigned int j;\n                long signed int sum = 0;\n                sum = (long signed int)conn->last_sendqueue_size[(pos) % CONGESTION_QUEUE_ARRAY_SIZE] -\n                      (long signed int)conn->last_sendqueue_size[(pos - (CONGESTION_QUEUE_ARRAY_SIZE - 1)) % CONGESTION_QUEUE_ARRAY_SIZE];\n\n                unsigned int n_p_pos = conn->last_sendqueue_counter % CONGESTION_LAST_SENT_ARRAY_SIZE;\n                conn->last_num_packets_sent[n_p_pos] = packets_sent;\n                conn->last_num_packets_resent[n_p_pos] = packets_resent;\n\n                _Bool direct_connected = 0;\n                crypto_connection_status(c, i, &direct_connected, NULL);\n\n                if (direct_connected && conn->last_tcp_sent + CONGESTION_EVENT_TIMEOUT > temp_time) {\n                    /* When switching from TCP to UDP, don't change the packet send rate for CONGESTION_EVENT_TIMEOUT ms. */\n                } else {\n                    long signed int total_sent = 0, total_resent = 0;\n\n                    //TODO use real delay\n                    unsigned int delay = (unsigned int)((conn->rtt_time / PACKET_COUNTER_AVERAGE_INTERVAL) + 0.5);\n                    unsigned int packets_set_rem_array = (CONGESTION_LAST_SENT_ARRAY_SIZE - CONGESTION_QUEUE_ARRAY_SIZE);\n\n                    if (delay > packets_set_rem_array) {\n                        delay = packets_set_rem_array;\n                    }\n\n                    for (j = 0; j < CONGESTION_QUEUE_ARRAY_SIZE; ++j) {\n                        unsigned int ind = (j + (packets_set_rem_array  - delay) + n_p_pos) % CONGESTION_LAST_SENT_ARRAY_SIZE;\n                        total_sent += conn->last_num_packets_sent[ind];\n                        total_resent += conn->last_num_packets_resent[ind];\n                    }\n\n                    if (sum > 0) {\n                        total_sent -= sum;\n                    } else {\n                        if (total_resent > -sum)\n                            total_resent = -sum;\n                    }\n\n                    /* if queue is too big only allow resending packets. */\n                    uint32_t npackets = num_packets_array(&conn->send_array);\n                    double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) *\n                                                 PACKET_COUNTER_AVERAGE_INTERVAL));\n\n                    double min_speed_request = 1000.0 * (((double)(total_sent + total_resent)) / ((double)(\n                            CONGESTION_QUEUE_ARRAY_SIZE) * PACKET_COUNTER_AVERAGE_INTERVAL));\n\n                    if (min_speed < CRYPTO_PACKET_MIN_RATE)\n                        min_speed = CRYPTO_PACKET_MIN_RATE;\n\n                    double send_array_ratio = (((double)npackets) / min_speed);\n\n                    //TODO: Improve formula?\n                    if (send_array_ratio > SEND_QUEUE_RATIO && CRYPTO_MIN_QUEUE_LENGTH < npackets) {\n                        conn->packet_send_rate = min_speed * (1.0 / (send_array_ratio / SEND_QUEUE_RATIO));\n                    } else if (conn->last_congestion_event + CONGESTION_EVENT_TIMEOUT < temp_time) {\n                        conn->packet_send_rate = min_speed * 1.2;\n                    } else {\n                        conn->packet_send_rate = min_speed * 0.9;\n                    }\n\n                    conn->packet_send_rate_requested = min_speed_request * 1.2;\n\n                    if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) {\n                        conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;\n                    }\n\n                    if (conn->packet_send_rate_requested < conn->packet_send_rate) {\n                        conn->packet_send_rate_requested = conn->packet_send_rate;\n                    }\n                }\n\n            }\n\n            if (conn->last_packets_left_set == 0 || conn->last_packets_left_requested_set == 0) {\n                conn->last_packets_left_requested_set = conn->last_packets_left_set = temp_time;\n                conn->packets_left_requested = conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH;\n            } else {\n                if (((uint64_t)((1000.0 / conn->packet_send_rate) + 0.5) + conn->last_packets_left_set) <= temp_time) {\n                    double n_packets = conn->packet_send_rate * (((double)(temp_time - conn->last_packets_left_set)) / 1000.0);\n                    n_packets += conn->last_packets_left_rem;\n\n                    uint32_t num_packets = n_packets;\n                    double rem = n_packets - (double)num_packets;\n\n                    if (conn->packets_left > num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH) {\n                        conn->packets_left = num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH;\n                    } else {\n                        conn->packets_left += num_packets;\n                    }\n\n                    conn->last_packets_left_set = temp_time;\n                    conn->last_packets_left_rem = rem;\n                }\n\n                if (((uint64_t)((1000.0 / conn->packet_send_rate_requested) + 0.5) + conn->last_packets_left_requested_set) <=\n                        temp_time) {\n                    double n_packets = conn->packet_send_rate_requested * (((double)(temp_time - conn->last_packets_left_requested_set)) /\n                                       1000.0);\n                    n_packets += conn->last_packets_left_requested_rem;\n\n                    uint32_t num_packets = n_packets;\n                    double rem = n_packets - (double)num_packets;\n                    conn->packets_left_requested = num_packets;\n\n                    conn->last_packets_left_requested_set = temp_time;\n                    conn->last_packets_left_requested_rem = rem;\n                }\n\n                if (conn->packets_left > conn->packets_left_requested)\n                    conn->packets_left_requested = conn->packets_left;\n            }\n\n            int ret = send_requested_packets(c, i, conn->packets_left_requested);\n\n            if (ret != -1) {\n                conn->packets_left_requested -= ret;\n                conn->packets_resent += ret;\n\n                if ((unsigned int)ret < conn->packets_left) {\n                    conn->packets_left -= ret;\n                } else {\n                    conn->last_congestion_event = temp_time;\n                    conn->packets_left = 0;\n                }\n            }\n\n            if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) {\n                total_send_rate += conn->packet_send_rate;\n            }\n        }\n    }\n\n    c->current_sleep_time = ~0;\n    uint32_t sleep_time = peak_request_packet_interval;\n\n    if (c->current_sleep_time > sleep_time) {\n        c->current_sleep_time = sleep_time;\n    }\n\n    if (total_send_rate > CRYPTO_PACKET_MIN_RATE) {\n        sleep_time = (1000.0 / total_send_rate);\n\n        if (c->current_sleep_time > sleep_time) {\n            c->current_sleep_time = sleep_time + 1;\n        }\n    }\n\n    sleep_time = CRYPTO_SEND_PACKET_INTERVAL;\n\n    if (c->current_sleep_time > sleep_time) {\n        c->current_sleep_time = sleep_time;\n    }\n}\n\n/* Return 1 if max speed was reached for this connection (no more data can be physically through the pipe).\n * Return 0 if it wasn't reached.\n */\n_Bool max_speed_reached(Net_Crypto *c, int crypt_connection_id)\n{\n    return reset_max_speed_reached(c, crypt_connection_id) != 0;\n}\n\n/* returns the number of packet slots left in the sendbuffer.\n * return 0 if failure.\n */\nuint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connection_id)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return 0;\n\n    uint32_t max_packets = CRYPTO_PACKET_BUFFER_SIZE - num_packets_array(&conn->send_array);\n\n    if (conn->packets_left < max_packets) {\n        return conn->packets_left;\n    } else {\n        return max_packets;\n    }\n}\n\n/* Sends a lossless cryptopacket.\n *\n * return -1 if data could not be put in packet queue.\n * return positive packet number if data was put into the queue.\n *\n * congestion_control: should congestion control apply to this packet?\n */\nint64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length,\n                          uint8_t congestion_control)\n{\n    if (length == 0)\n        return -1;\n\n    if (data[0] < CRYPTO_RESERVED_PACKETS)\n        return -1;\n\n    if (data[0] >= PACKET_ID_LOSSY_RANGE_START)\n        return -1;\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    if (conn->status != CRYPTO_CONN_ESTABLISHED)\n        return -1;\n\n    if (congestion_control && conn->packets_left == 0)\n        return -1;\n\n    int64_t ret = send_lossless_packet(c, crypt_connection_id, data, length, congestion_control);\n\n    if (ret == -1)\n        return -1;\n\n    if (congestion_control) {\n        --conn->packets_left;\n        --conn->packets_left_requested;\n        conn->packets_sent++;\n    }\n\n    return ret;\n}\n\n/* Check if packet_number was received by the other side.\n *\n * packet_number must be a valid packet number of a packet sent on this connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet_number)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return -1;\n\n    uint32_t num = conn->send_array.buffer_end - conn->send_array.buffer_start;\n    uint32_t num1 = packet_number - conn->send_array.buffer_start;\n\n    if (num < num1) {\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n/* return -1 on failure.\n * return 0 on success.\n *\n * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*)\n */\nint send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length)\n{\n    if (length == 0 || length > MAX_CRYPTO_DATA_SIZE)\n        return -1;\n\n    if (data[0] < PACKET_ID_LOSSY_RANGE_START)\n        return -1;\n\n    if (data[0] >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE))\n        return -1;\n\n    pthread_mutex_lock(&c->connections_mutex);\n    ++c->connection_use_counter;\n    pthread_mutex_unlock(&c->connections_mutex);\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    int ret = -1;\n\n    if (conn) {\n        pthread_mutex_lock(&conn->mutex);\n        uint32_t buffer_start = conn->recv_array.buffer_start;\n        uint32_t buffer_end = conn->send_array.buffer_end;\n        pthread_mutex_unlock(&conn->mutex);\n        ret = send_data_packet_helper(c, crypt_connection_id, buffer_start, buffer_end, data, length);\n    }\n\n    pthread_mutex_lock(&c->connections_mutex);\n    --c->connection_use_counter;\n    pthread_mutex_unlock(&c->connections_mutex);\n\n    return ret;\n}\n\n/* Kill a crypto connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint crypto_kill(Net_Crypto *c, int crypt_connection_id)\n{\n    while (1) { /* TODO: is this really the best way to do this? */\n        pthread_mutex_lock(&c->connections_mutex);\n\n        if (!c->connection_use_counter) {\n            break;\n        }\n\n        pthread_mutex_unlock(&c->connections_mutex);\n    }\n\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    int ret = -1;\n\n    if (conn) {\n        if (conn->status == CRYPTO_CONN_ESTABLISHED)\n            send_kill_packet(c, crypt_connection_id);\n\n        pthread_mutex_lock(&c->tcp_mutex);\n        kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp);\n        pthread_mutex_unlock(&c->tcp_mutex);\n\n        bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id);\n        bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id);\n        clear_temp_packet(c, crypt_connection_id);\n        clear_buffer(&conn->send_array);\n        clear_buffer(&conn->recv_array);\n        ret = wipe_crypto_connection(c, crypt_connection_id);\n    }\n\n    pthread_mutex_unlock(&c->connections_mutex);\n\n    return ret;\n}\n\n/* return one of CRYPTO_CONN_* values indicating the state of the connection.\n *\n * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't.\n * sets online_tcp_relays to the number of connected tcp relays this connection has.\n */\nunsigned int crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, _Bool *direct_connected,\n                                      unsigned int *online_tcp_relays)\n{\n    Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);\n\n    if (conn == 0)\n        return CRYPTO_CONN_NO_CONNECTION;\n\n    if (direct_connected) {\n        *direct_connected = 0;\n\n        uint64_t current_time = unix_time();\n\n        if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev4) > current_time)\n            *direct_connected = 1;\n\n        if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev6) > current_time)\n            *direct_connected = 1;\n    }\n\n    if (online_tcp_relays) {\n        *online_tcp_relays = tcp_connection_to_online_tcp_relays(c->tcp_c, conn->connection_number_tcp);\n    }\n\n    return conn->status;\n}\n\nvoid new_keys(Net_Crypto *c)\n{\n    crypto_box_keypair(c->self_public_key, c->self_secret_key);\n}\n\n/* Save the public and private keys to the keys array.\n * Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES.\n *\n * TODO: Save only secret key.\n */\nvoid save_keys(const Net_Crypto *c, uint8_t *keys)\n{\n    memcpy(keys, c->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(keys + crypto_box_PUBLICKEYBYTES, c->self_secret_key, crypto_box_SECRETKEYBYTES);\n}\n\n/* Load the secret key.\n * Length must be crypto_box_SECRETKEYBYTES.\n */\nvoid load_secret_key(Net_Crypto *c, const uint8_t *sk)\n{\n    memcpy(c->self_secret_key, sk, crypto_box_SECRETKEYBYTES);\n    crypto_scalarmult_curve25519_base(c->self_public_key, c->self_secret_key);\n}\n\n/* Run this to (re)initialize net_crypto.\n * Sets all the global connection variables to their default values.\n */\nNet_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info)\n{\n    unix_time_update();\n\n    if (dht == NULL)\n        return NULL;\n\n    Net_Crypto *temp = calloc(1, sizeof(Net_Crypto));\n\n    if (temp == NULL)\n        return NULL;\n\n    temp->tcp_c = new_tcp_connections(dht->self_secret_key, proxy_info);\n\n    if (temp->tcp_c == NULL) {\n        free(temp);\n        return NULL;\n    }\n\n    set_packet_tcp_connection_callback(temp->tcp_c, &tcp_data_callback, temp);\n    set_oob_packet_tcp_connection_callback(temp->tcp_c, &tcp_oob_callback, temp);\n\n    if (create_recursive_mutex(&temp->tcp_mutex) != 0 ||\n            pthread_mutex_init(&temp->connections_mutex, NULL) != 0) {\n        kill_tcp_connections(temp->tcp_c);\n        free(temp);\n        return NULL;\n    }\n\n    temp->dht = dht;\n\n    new_keys(temp);\n    new_symmetric_key(temp->secret_symmetric_key);\n\n    temp->current_sleep_time = CRYPTO_SEND_PACKET_INTERVAL;\n\n    networking_registerhandler(dht->net, NET_PACKET_COOKIE_REQUEST, &udp_handle_cookie_request, temp);\n    networking_registerhandler(dht->net, NET_PACKET_COOKIE_RESPONSE, &udp_handle_packet, temp);\n    networking_registerhandler(dht->net, NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp);\n    networking_registerhandler(dht->net, NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp);\n\n    bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8);\n\n    return temp;\n}\n\nstatic void kill_timedout(Net_Crypto *c)\n{\n    uint32_t i;\n    //uint64_t temp_time = current_time_monotonic();\n\n    for (i = 0; i < c->crypto_connections_length; ++i) {\n        Crypto_Connection *conn = get_crypto_connection(c, i);\n\n        if (conn == 0)\n            return;\n\n        if (conn->status == CRYPTO_CONN_NO_CONNECTION)\n            continue;\n\n        if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT\n                || conn->status == CRYPTO_CONN_NOT_CONFIRMED) {\n            if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES)\n                continue;\n\n            connection_kill(c, i);\n\n        }\n\n        if (conn->status == CRYPTO_CONN_ESTABLISHED) {\n            //TODO: add a timeout here?\n        }\n    }\n}\n\n/* return the optimal interval in ms for running do_net_crypto.\n */\nuint32_t crypto_run_interval(const Net_Crypto *c)\n{\n    return c->current_sleep_time;\n}\n\n/* Main loop. */\nvoid do_net_crypto(Net_Crypto *c)\n{\n    unix_time_update();\n    kill_timedout(c);\n    do_tcp(c);\n    send_crypto_packets(c);\n}\n\nvoid kill_net_crypto(Net_Crypto *c)\n{\n    uint32_t i;\n\n    for (i = 0; i < c->crypto_connections_length; ++i) {\n        crypto_kill(c, i);\n    }\n\n    pthread_mutex_destroy(&c->tcp_mutex);\n    pthread_mutex_destroy(&c->connections_mutex);\n\n    kill_tcp_connections(c->tcp_c);\n    bs_list_free(&c->ip_port_list);\n    networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_REQUEST, NULL, NULL);\n    networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_RESPONSE, NULL, NULL);\n    networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_HS, NULL, NULL);\n    networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_DATA, NULL, NULL);\n    sodium_memzero(c, sizeof(Net_Crypto));\n    free(c);\n}\n"
  },
  {
    "path": "toxcore/net_crypto.h",
    "content": "/* net_crypto.h\n *\n * Functions for the core network crypto.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef NET_CRYPTO_H\n#define NET_CRYPTO_H\n\n#include \"DHT.h\"\n#include \"LAN_discovery.h\"\n#include \"TCP_connection.h\"\n#include <pthread.h>\n\n#define CRYPTO_CONN_NO_CONNECTION 0\n#define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets\n#define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets\n#define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets, we have received one from the other\n#define CRYPTO_CONN_ESTABLISHED 4\n\n/* Maximum size of receiving and sending packet buffers. */\n#define CRYPTO_PACKET_BUFFER_SIZE 32768 /* Must be a power of 2 */\n\n/* Minimum packet rate per second. */\n#define CRYPTO_PACKET_MIN_RATE 4.0\n\n/* Minimum packet queue max length. */\n#define CRYPTO_MIN_QUEUE_LENGTH 64\n\n/* Maximum total size of packets that net_crypto sends. */\n#define MAX_CRYPTO_PACKET_SIZE 1400\n\n#define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + crypto_box_MACBYTES)\n\n/* Max size of data in packets */\n#define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE)\n\n/* Interval in ms between sending cookie request/handshake packets. */\n#define CRYPTO_SEND_PACKET_INTERVAL 1000\n\n/* The maximum number of times we try to send the cookie request and handshake\n   before giving up. */\n#define MAX_NUM_SENDPACKET_TRIES 8\n\n/* The timeout of no received UDP packets before the direct UDP connection is considered dead. */\n#define UDP_DIRECT_TIMEOUT ((MAX_NUM_SENDPACKET_TRIES * CRYPTO_SEND_PACKET_INTERVAL) / 1000)\n\n#define PACKET_ID_PADDING 0 /* Denotes padding */\n#define PACKET_ID_REQUEST 1 /* Used to request unreceived packets */\n#define PACKET_ID_KILL    2 /* Used to kill connection */\n\n/* Packet ids 0 to CRYPTO_RESERVED_PACKETS - 1 are reserved for use by net_crypto. */\n#define CRYPTO_RESERVED_PACKETS 16\n\n#define MAX_TCP_CONNECTIONS 64\n#define MAX_TCP_RELAYS_PEER 4\n\n/* All packets starting with a byte in this range are considered lossy packets. */\n#define PACKET_ID_LOSSY_RANGE_START 192\n#define PACKET_ID_LOSSY_RANGE_SIZE 63\n\n#define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */\n\n/* Base current transfer speed on last CONGESTION_QUEUE_ARRAY_SIZE number of points taken\n   at the dT defined in net_crypto.c */\n#define CONGESTION_QUEUE_ARRAY_SIZE 12\n#define CONGESTION_LAST_SENT_ARRAY_SIZE (CONGESTION_QUEUE_ARRAY_SIZE * 2)\n\n/* Default connection ping in ms. */\n#define DEFAULT_PING_CONNECTION 1000\n#define DEFAULT_TCP_PING_CONNECTION 500\n\ntypedef struct {\n    uint64_t sent_time;\n    uint16_t length;\n    uint8_t data[MAX_CRYPTO_DATA_SIZE];\n} Packet_Data;\n\ntypedef struct {\n    Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE];\n    uint32_t  buffer_start;\n    uint32_t  buffer_end; /* packet numbers in array: {buffer_start, buffer_end) */\n} Packets_Array;\n\ntypedef struct {\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */\n    uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */\n    uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */\n    uint8_t sessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* Our public key for this session. */\n    uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* Our private key for this session. */\n    uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */\n    uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* The precomputed shared key from encrypt_precompute. */\n    uint8_t status; /* 0 if no connection, 1 we are sending cookie request packets,\n                     * 2 if we are sending handshake packets\n                     * 3 if connection is not confirmed yet (we have received a handshake but no data packets yet),\n                     * 4 if the connection is established.\n                     */\n    uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */\n    uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */\n\n    uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */\n    uint16_t temp_packet_length;\n    uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */\n    uint32_t temp_packet_num_sent;\n\n    IP_Port ip_portv4; /* The ip and port to contact this guy directly.*/\n    IP_Port ip_portv6;\n    uint64_t direct_lastrecv_timev4; /* The Time at which we last received a direct packet in ms. */\n    uint64_t direct_lastrecv_timev6;\n\n    uint64_t last_tcp_sent; /* Time the last TCP packet was sent. */\n\n    Packets_Array send_array;\n    Packets_Array recv_array;\n\n    int (*connection_status_callback)(void *object, int id, uint8_t status);\n    void *connection_status_callback_object;\n    int connection_status_callback_id;\n\n    int (*connection_data_callback)(void *object, int id, uint8_t *data, uint16_t length);\n    void *connection_data_callback_object;\n    int connection_data_callback_id;\n\n    int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length);\n    void *connection_lossy_data_callback_object;\n    int connection_lossy_data_callback_id;\n\n    uint64_t last_request_packet_sent;\n    uint64_t direct_send_attempt_time;\n\n    uint32_t packet_counter;\n    double packet_recv_rate;\n    uint64_t packet_counter_set;\n\n    double packet_send_rate;\n    uint32_t packets_left;\n    uint64_t last_packets_left_set;\n    double last_packets_left_rem;\n\n    double packet_send_rate_requested;\n    uint32_t packets_left_requested;\n    uint64_t last_packets_left_requested_set;\n    double last_packets_left_requested_rem;\n\n    uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter;\n    long signed int last_num_packets_sent[CONGESTION_LAST_SENT_ARRAY_SIZE],\n         last_num_packets_resent[CONGESTION_LAST_SENT_ARRAY_SIZE];\n    uint32_t packets_sent, packets_resent;\n    uint64_t last_congestion_event;\n    uint64_t rtt_time;\n\n    /* TCP_connection connection_number */\n    unsigned int connection_number_tcp;\n\n    uint8_t maximum_speed_reached;\n\n    pthread_mutex_t mutex;\n\n    void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key);\n    void *dht_pk_callback_object;\n    uint32_t dht_pk_callback_number;\n} Crypto_Connection;\n\ntypedef struct {\n    IP_Port source;\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */\n    uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer. */\n    uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */\n    uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */\n    uint8_t *cookie;\n    uint8_t cookie_length;\n} New_Connection;\n\ntypedef struct {\n    DHT *dht;\n    TCP_Connections *tcp_c;\n\n    Crypto_Connection *crypto_connections;\n    pthread_mutex_t tcp_mutex;\n\n    pthread_mutex_t connections_mutex;\n    unsigned int connection_use_counter;\n\n    uint32_t crypto_connections_length; /* Length of connections array. */\n\n    /* Our public and secret keys. */\n    uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];\n\n    /* The secret key used for cookies */\n    uint8_t secret_symmetric_key[crypto_box_KEYBYTES];\n\n    int (*new_connection_callback)(void *object, New_Connection *n_c);\n    void *new_connection_callback_object;\n\n    /* The current optimal sleep time */\n    uint32_t current_sleep_time;\n\n    BS_LIST ip_port_list;\n} Net_Crypto;\n\n\n/* Set function to be called when someone requests a new connection to us.\n *\n * The set function should return -1 on failure and 0 on success.\n *\n * n_c is only valid for the duration of the function call.\n */\nvoid new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c),\n                            void *object);\n\n/* Accept a crypto connection.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nint accept_crypto_connection(Net_Crypto *c, New_Connection *n_c);\n\n/* Create a crypto connection.\n * If one to that real public key already exists, return it.\n *\n * return -1 on failure.\n * return connection id on success.\n */\nint new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key);\n\n/* Set the direct ip of the crypto connection.\n *\n * Connected is 0 if we are not sure we are connected to that person, 1 if we are sure.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, _Bool connected);\n\n/* Set function to be called when connection with crypt_connection_id goes connects/disconnects.\n *\n * The set function should return -1 on failure and 0 on success.\n * Note that if this function is set, the connection will clear itself on disconnect.\n * Object and id will be passed to this function untouched.\n * status is 1 if the connection is going online, 0 if it is going offline.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint connection_status_handler(const Net_Crypto *c, int crypt_connection_id,\n                              int (*connection_status_callback)(void *object, int id, uint8_t status), void *object, int id);\n\n/* Set function to be called when connection with crypt_connection_id receives a lossless data packet of length.\n *\n * The set function should return -1 on failure and 0 on success.\n * Object and id will be passed to this function untouched.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint connection_data_handler(const Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object,\n                            int id, uint8_t *data, uint16_t length), void *object, int id);\n\n\n/* Set function to be called when connection with crypt_connection_id receives a lossy data packet of length.\n *\n * The set function should return -1 on failure and 0 on success.\n * Object and id will be passed to this function untouched.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id,\n                                  int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object,\n                                  int id);\n\n/* Set the function for this friend that will be callbacked with object and number if\n * the friend sends us a different dht public key than we have associated to him.\n *\n * If this function is called, the connection should be recreated with the new public key.\n *\n * object and number will be passed as argument to this function.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number,\n                       const uint8_t *dht_public_key), void *object, uint32_t number);\n\n/* returns the number of packet slots left in the sendbuffer.\n * return 0 if failure.\n */\nuint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connection_id);\n\n/* Return 1 if max speed was reached for this connection (no more data can be physically through the pipe).\n * Return 0 if it wasn't reached.\n */\n_Bool max_speed_reached(Net_Crypto *c, int crypt_connection_id);\n\n/* Sends a lossless cryptopacket.\n *\n * return -1 if data could not be put in packet queue.\n * return positive packet number if data was put into the queue.\n *\n * The first byte of data must be in the CRYPTO_RESERVED_PACKETS to PACKET_ID_LOSSY_RANGE_START range.\n *\n * congestion_control: should congestion control apply to this packet?\n */\nint64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length,\n                          uint8_t congestion_control);\n\n/* Check if packet_number was received by the other side.\n *\n * packet_number must be a valid packet number of a packet sent on this connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet_number);\n\n/* return -1 on failure.\n * return 0 on success.\n *\n * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*)\n */\nint send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length);\n\n/* Add a tcp relay, associating it to a crypt_connection_id.\n *\n * return 0 if it was added.\n * return -1 if it wasn't.\n */\nint add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, const uint8_t *public_key);\n\n/* Add a tcp relay to the array.\n *\n * return 0 if it was added.\n * return -1 if it wasn't.\n */\nint add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key);\n\n/* Return a random TCP connection number for use in send_tcp_onion_request.\n *\n * return TCP connection number on success.\n * return -1 on failure.\n */\nint get_random_tcp_con_number(Net_Crypto *c);\n\n/* Send an onion packet via the TCP relay corresponding to TCP_conn_number.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint send_tcp_onion_request(Net_Crypto *c, unsigned int TCP_conn_number, const uint8_t *data, uint16_t length);\n\n/* Copy a maximum of num TCP relays we are connected to to tcp_relays.\n * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.\n *\n * return number of relays copied to tcp_relays on success.\n * return 0 on failure.\n */\nunsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num);\n\n/* Kill a crypto connection.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint crypto_kill(Net_Crypto *c, int crypt_connection_id);\n\n/* return one of CRYPTO_CONN_* values indicating the state of the connection.\n *\n * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't.\n * sets online_tcp_relays to the number of connected tcp relays this connection has.\n */\nunsigned int crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, _Bool *direct_connected,\n                                      unsigned int *online_tcp_relays);\n\n/* Generate our public and private keys.\n *  Only call this function the first time the program starts.\n */\nvoid new_keys(Net_Crypto *c);\n\n/* Save the public and private keys to the keys array.\n *  Length must be crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES.\n */\nvoid save_keys(const Net_Crypto *c, uint8_t *keys);\n\n/* Load the secret key.\n * Length must be crypto_box_SECRETKEYBYTES.\n */\nvoid load_secret_key(Net_Crypto *c, const uint8_t *sk);\n\n/* Create new instance of Net_Crypto.\n *  Sets all the global connection variables to their default values.\n */\nNet_Crypto *new_net_crypto(DHT *dht, TCP_Proxy_Info *proxy_info);\n\n/* return the optimal interval in ms for running do_net_crypto.\n */\nuint32_t crypto_run_interval(const Net_Crypto *c);\n\n/* Main loop. */\nvoid do_net_crypto(Net_Crypto *c);\n\nvoid kill_net_crypto(Net_Crypto *c);\n\n\n\n#endif\n"
  },
  {
    "path": "toxcore/network.c",
    "content": "/* network.c\n *\n * Functions for the core networking.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#if (_WIN32_WINNT >= _WIN32_WINNT_WINXP)\n#define _WIN32_WINNT  0x501\n#endif\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"logger.h\"\n\n#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)\n#include <errno.h>\n#endif\n\n#ifdef __APPLE__\n#include <mach/clock.h>\n#include <mach/mach.h>\n#endif\n\n#include \"network.h\"\n#include \"util.h\"\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n\nstatic const char *inet_ntop(sa_family_t family, void *addr, char *buf, size_t bufsize)\n{\n    if (family == AF_INET) {\n        struct sockaddr_in saddr;\n        memset(&saddr, 0, sizeof(saddr));\n\n        saddr.sin_family = AF_INET;\n        saddr.sin_addr = *(struct in_addr *)addr;\n\n        DWORD len = bufsize;\n\n        if (WSAAddressToString((LPSOCKADDR)&saddr, sizeof(saddr), NULL, buf, &len))\n            return NULL;\n\n        return buf;\n    } else if (family == AF_INET6) {\n        struct sockaddr_in6 saddr;\n        memset(&saddr, 0, sizeof(saddr));\n\n        saddr.sin6_family = AF_INET6;\n        saddr.sin6_addr = *(struct in6_addr *)addr;\n\n        DWORD len = bufsize;\n\n        if (WSAAddressToString((LPSOCKADDR)&saddr, sizeof(saddr), NULL, buf, &len))\n            return NULL;\n\n        return buf;\n    }\n\n    return NULL;\n}\n\nstatic int inet_pton(sa_family_t family, const char *addrString, void *addrbuf)\n{\n    if (family == AF_INET) {\n        struct sockaddr_in saddr;\n        memset(&saddr, 0, sizeof(saddr));\n\n        INT len = sizeof(saddr);\n\n        if (WSAStringToAddress((LPTSTR)addrString, AF_INET, NULL, (LPSOCKADDR)&saddr, &len))\n            return 0;\n\n        *(struct in_addr *)addrbuf = saddr.sin_addr;\n\n        return 1;\n    } else if (family == AF_INET6) {\n        struct sockaddr_in6 saddr;\n        memset(&saddr, 0, sizeof(saddr));\n\n        INT len = sizeof(saddr);\n\n        if (WSAStringToAddress((LPTSTR)addrString, AF_INET6, NULL, (LPSOCKADDR)&saddr, &len))\n            return 0;\n\n        *(struct in6_addr *)addrbuf = saddr.sin6_addr;\n\n        return 1;\n    }\n\n    return 0;\n}\n\n#endif\n\n/* Check if socket is valid.\n *\n * return 1 if valid\n * return 0 if not valid\n */\nint sock_valid(sock_t sock)\n{\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n\n    if (sock == INVALID_SOCKET) {\n#else\n\n    if (sock < 0) {\n#endif\n        return 0;\n    }\n\n    return 1;\n}\n\n/* Close the socket.\n */\nvoid kill_sock(sock_t sock)\n{\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    closesocket(sock);\n#else\n    close(sock);\n#endif\n}\n\n/* Set socket as nonblocking\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_nonblock(sock_t sock)\n{\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    u_long mode = 1;\n    return (ioctlsocket(sock, FIONBIO, &mode) == 0);\n#else\n    return (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == 0);\n#endif\n}\n\n/* Set socket to not emit SIGPIPE\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_nosigpipe(sock_t sock)\n{\n#if defined(__MACH__)\n    int set = 1;\n    return (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)) == 0);\n#else\n    return 1;\n#endif\n}\n\n/* Enable SO_REUSEADDR on socket.\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_reuseaddr(sock_t sock)\n{\n    int set = 1;\n    return (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(set)) == 0);\n}\n\n/* Set socket to dual (IPv4 + IPv6 socket)\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_dualstack(sock_t sock)\n{\n    int ipv6only = 0;\n    socklen_t optsize = sizeof(ipv6only);\n    int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&ipv6only, &optsize);\n\n    if ((res == 0) && (ipv6only == 0))\n        return 1;\n\n    ipv6only = 0;\n    return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&ipv6only, sizeof(ipv6only)) == 0);\n}\n\n\n/*  return current UNIX time in microseconds (us). */\nstatic uint64_t current_time_actual(void)\n{\n    uint64_t time;\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    /* This probably works fine */\n    FILETIME ft;\n    GetSystemTimeAsFileTime(&ft);\n    time = ft.dwHighDateTime;\n    time <<= 32;\n    time |= ft.dwLowDateTime;\n    time -= 116444736000000000ULL;\n    return time / 10;\n#else\n    struct timeval a;\n    gettimeofday(&a, NULL);\n    time = 1000000ULL * a.tv_sec + a.tv_usec;\n    return time;\n#endif\n}\n\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\nstatic uint64_t last_monotime;\nstatic uint64_t add_monotime;\n#endif\n\n/* return current monotonic time in milliseconds (ms). */\nuint64_t current_time_monotonic(void)\n{\n    uint64_t time;\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    time = (uint64_t)GetTickCount() + add_monotime;\n\n    if (time < last_monotime) { /* Prevent time from ever decreasing because of 32 bit wrap. */\n        uint32_t add = ~0;\n        add_monotime += add;\n        time += add;\n    }\n\n    last_monotime = time;\n#else\n    struct timespec monotime;\n#if defined(__linux__) && defined(CLOCK_MONOTONIC_RAW)\n    clock_gettime(CLOCK_MONOTONIC_RAW, &monotime);\n#elif defined(__APPLE__)\n    clock_serv_t muhclock;\n    mach_timespec_t machtime;\n\n    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock);\n    clock_get_time(muhclock, &machtime);\n    mach_port_deallocate(mach_task_self(), muhclock);\n\n    monotime.tv_sec = machtime.tv_sec;\n    monotime.tv_nsec = machtime.tv_nsec;\n#else\n    clock_gettime(CLOCK_MONOTONIC, &monotime);\n#endif\n    time = 1000ULL * monotime.tv_sec + (monotime.tv_nsec / 1000000ULL);\n#endif\n    return time;\n}\n\n/* In case no logging */\n#ifndef TOX_LOGGER\n#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__)\n#else\n#define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0\n#define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0\n\n#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__) \\\n    (__ip_port__) .ip; \\\n    if (__res__ < 0) /* Windows doesn't necessarily know %zu */ \\\n        LOGGER_TRACE(\"[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x\", \\\n                 __buffer__[0], __message__, (__buflen__ < 999 ? (uint16_t)__buflen__ : 999), 'E', \\\n                 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), errno, strerror(errno), data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \\\n    else if ((__res__ > 0) && ((size_t)__res__ <= __buflen__)) \\\n        LOGGER_TRACE(\"[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x\", \\\n                 __buffer__[0], __message__, (__res__ < 999 ? (size_t)__res__ : 999), ((size_t)__res__ < __buflen__ ? '<' : '='), \\\n                 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, \"OK\", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__)); \\\n    else /* empty or overwrite */ \\\n        LOGGER_TRACE(\"[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x\", \\\n                 __buffer__[0], __message__, (size_t)__res__, (!__res__ ? '!' : '>'), __buflen__, \\\n                 ip_ntoa(&((__ip_port__).ip)), ntohs((__ip_port__).port), 0, \"OK\", data_0(__buflen__, __buffer__), data_1(__buflen__, __buffer__));\n\n#endif /* TOX_LOGGER */\n\n/* Basic network functions:\n * Function to send packet(data) of length length to ip_port.\n */\nint sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length)\n{\n    if (net->family == 0) /* Socket not initialized */\n        return -1;\n\n    /* socket AF_INET, but target IP NOT: can't send */\n    if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET))\n        return -1;\n\n    struct sockaddr_storage addr;\n    size_t addrsize = 0;\n\n    if (ip_port.ip.family == AF_INET) {\n        if (net->family == AF_INET6) {\n            /* must convert to IPV4-in-IPV6 address */\n            struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;\n\n            addrsize = sizeof(struct sockaddr_in6);\n            addr6->sin6_family = AF_INET6;\n            addr6->sin6_port = ip_port.port;\n\n            /* there should be a macro for this in a standards compliant\n             * environment, not found */\n            IP6 ip6;\n\n            ip6.uint32[0] = 0;\n            ip6.uint32[1] = 0;\n            ip6.uint32[2] = htonl(0xFFFF);\n            ip6.uint32[3] = ip_port.ip.ip4.uint32;\n            addr6->sin6_addr = ip6.in6_addr;\n\n            addr6->sin6_flowinfo = 0;\n            addr6->sin6_scope_id = 0;\n        } else {\n            struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;\n\n            addrsize = sizeof(struct sockaddr_in);\n            addr4->sin_family = AF_INET;\n            addr4->sin_addr = ip_port.ip.ip4.in_addr;\n            addr4->sin_port = ip_port.port;\n        }\n    } else if (ip_port.ip.family == AF_INET6) {\n        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in6);\n        addr6->sin6_family = AF_INET6;\n        addr6->sin6_port = ip_port.port;\n        addr6->sin6_addr = ip_port.ip.ip6.in6_addr;\n\n        addr6->sin6_flowinfo = 0;\n        addr6->sin6_scope_id = 0;\n    } else {\n        /* unknown address type*/\n        return -1;\n    }\n\n    int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);\n\n    loglogdata(\"O=>\", data, length, ip_port, res);\n\n    return res;\n}\n\n/* Function to receive data\n *  ip and port of sender is put into ip_port.\n *  Packet data is put into data.\n *  Packet length is put into length.\n */\nstatic int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)\n{\n    memset(ip_port, 0, sizeof(IP_Port));\n    struct sockaddr_storage addr;\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    int addrlen = sizeof(addr);\n#else\n    socklen_t addrlen = sizeof(addr);\n#endif\n    *length = 0;\n    int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);\n\n    if (fail_or_len < 0) {\n\n        LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK))\n                      LOGGER_ERROR(\"Unexpected error reading from socket: %u, %s\\n\", errno, strerror(errno)); );\n\n        return -1; /* Nothing received. */\n    }\n\n    *length = (uint32_t)fail_or_len;\n\n    if (addr.ss_family == AF_INET) {\n        struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;\n\n        ip_port->ip.family = addr_in->sin_family;\n        ip_port->ip.ip4.in_addr = addr_in->sin_addr;\n        ip_port->port = addr_in->sin_port;\n    } else if (addr.ss_family == AF_INET6) {\n        struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr;\n        ip_port->ip.family = addr_in6->sin6_family;\n        ip_port->ip.ip6.in6_addr = addr_in6->sin6_addr;\n        ip_port->port = addr_in6->sin6_port;\n\n        if (IPV6_IPV4_IN_V6(ip_port->ip.ip6)) {\n            ip_port->ip.family = AF_INET;\n            ip_port->ip.ip4.uint32 = ip_port->ip.ip6.uint32[3];\n        }\n    } else\n        return -1;\n\n    loglogdata(\"=>O\", data, MAX_UDP_PACKET_SIZE, *ip_port, *length);\n\n    return 0;\n}\n\nvoid networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object)\n{\n    net->packethandlers[byte].function = cb;\n    net->packethandlers[byte].object = object;\n}\n\nvoid networking_poll(Networking_Core *net)\n{\n    if (net->family == 0) /* Socket not initialized */\n        return;\n\n    unix_time_update();\n\n    IP_Port ip_port;\n    uint8_t data[MAX_UDP_PACKET_SIZE];\n    uint32_t length;\n\n    while (receivepacket(net->sock, &ip_port, data, &length) != -1) {\n        if (length < 1) continue;\n\n        if (!(net->packethandlers[data[0]].function)) {\n            LOGGER_WARNING(\"[%02u] -- Packet has no handler\", data[0]);\n            continue;\n        }\n\n        net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length);\n    }\n}\n\n#ifndef VANILLA_NACL\n/* Used for sodium_init() */\n#include <sodium.h>\n#endif\n\nuint8_t at_startup_ran = 0;\nint networking_at_startup(void)\n{\n    if (at_startup_ran != 0)\n        return 0;\n\n#ifndef VANILLA_NACL\n\n#ifdef USE_RANDOMBYTES_STIR\n    randombytes_stir();\n#else\n    sodium_init();\n#endif /*USE_RANDOMBYTES_STIR*/\n\n#endif/*VANILLA_NACL*/\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    WSADATA wsaData;\n\n    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR)\n        return -1;\n\n#endif\n    srand((uint32_t)current_time_actual());\n    at_startup_ran = 1;\n    return 0;\n}\n\n/* TODO: Put this somewhere\nstatic void at_shutdown(void)\n{\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)\n    WSACleanup();\n#endif\n}\n*/\n\n/* Initialize networking.\n * Added for reverse compatibility with old new_networking calls.\n */\nNetworking_Core *new_networking(IP ip, uint16_t port)\n{\n    return new_networking_ex(ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), 0);\n}\n\n/* Initialize networking.\n * Bind to ip and port.\n * ip must be in network order EX: 127.0.0.1 = (7F000001).\n * port is in host byte order (this means don't worry about it).\n *\n *  return Networking_Core object if no problems\n *  return NULL if there are problems.\n *\n * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other.\n */\nNetworking_Core *new_networking_ex(IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error)\n{\n    /* If both from and to are 0, use default port range\n     * If one is 0 and the other is non-0, use the non-0 value as only port\n     * If from > to, swap\n     */\n    if (port_from == 0 && port_to == 0) {\n        port_from = TOX_PORTRANGE_FROM;\n        port_to = TOX_PORTRANGE_TO;\n    } else if (port_from == 0 && port_to != 0) {\n        port_from = port_to;\n    } else if (port_from != 0 && port_to == 0) {\n        port_to = port_from;\n    } else if (port_from > port_to) {\n        uint16_t temp = port_from;\n        port_from = port_to;\n        port_to = temp;\n    }\n\n    if (error)\n        *error = 2;\n\n    /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */\n    if (ip.family != AF_INET && ip.family != AF_INET6) {\n#ifdef DEBUG\n        fprintf(stderr, \"Invalid address family: %u\\n\", ip.family);\n#endif\n        return NULL;\n    }\n\n    if (networking_at_startup() != 0)\n        return NULL;\n\n    Networking_Core *temp = calloc(1, sizeof(Networking_Core));\n\n    if (temp == NULL)\n        return NULL;\n\n    temp->family = ip.family;\n    temp->port = 0;\n\n    /* Initialize our socket. */\n    /* add log message what we're creating */\n    temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP);\n\n    /* Check for socket error. */\n    if (!sock_valid(temp->sock)) {\n#ifdef DEBUG\n        fprintf(stderr, \"Failed to get a socket?! %u, %s\\n\", errno, strerror(errno));\n#endif\n        free(temp);\n\n        if (error)\n            *error = 1;\n\n        return NULL;\n    }\n\n    /* Functions to increase the size of the send and receive UDP buffers.\n     */\n    int n = 1024 * 1024 * 2;\n    setsockopt(temp->sock, SOL_SOCKET, SO_RCVBUF, (char *)&n, sizeof(n));\n    setsockopt(temp->sock, SOL_SOCKET, SO_SNDBUF, (char *)&n, sizeof(n));\n\n    /* Enable broadcast on socket */\n    int broadcast = 1;\n    setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));\n\n    /* iOS UDP sockets are weird and apparently can SIGPIPE */\n    if (!set_socket_nosigpipe(temp->sock)) {\n        kill_networking(temp);\n\n        if (error)\n            *error = 1;\n\n        return NULL;\n    }\n\n    /* Set socket nonblocking. */\n    if (!set_socket_nonblock(temp->sock)) {\n        kill_networking(temp);\n\n        if (error)\n            *error = 1;\n\n        return NULL;\n    }\n\n    /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */\n    uint16_t *portptr = NULL;\n    struct sockaddr_storage addr;\n    size_t addrsize;\n\n    if (temp->family == AF_INET) {\n        struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in);\n        addr4->sin_family = AF_INET;\n        addr4->sin_port = 0;\n        addr4->sin_addr = ip.ip4.in_addr;\n\n        portptr = &addr4->sin_port;\n    } else if (temp->family == AF_INET6) {\n        struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;\n\n        addrsize = sizeof(struct sockaddr_in6);\n        addr6->sin6_family = AF_INET6;\n        addr6->sin6_port = 0;\n        addr6->sin6_addr = ip.ip6.in6_addr;\n\n        addr6->sin6_flowinfo = 0;\n        addr6->sin6_scope_id = 0;\n\n        portptr = &addr6->sin6_port;\n    } else {\n        free(temp);\n        return NULL;\n    }\n\n    if (ip.family == AF_INET6) {\n#ifdef TOX_LOGGER\n        int is_dualstack =\n#endif /* TOX_LOGGER */\n            set_socket_dualstack(temp->sock);\n        LOGGER_DEBUG( \"Dual-stack socket: %s\",\n                      is_dualstack ? \"enabled\" : \"Failed to enable, won't be able to receive from/send to IPv4 addresses\" );\n        /* multicast local nodes */\n        struct ipv6_mreq mreq;\n        memset(&mreq, 0, sizeof(mreq));\n        mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF;\n        mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;\n        mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;\n        mreq.ipv6mr_interface = 0;\n#ifdef TOX_LOGGER\n        int res =\n#endif /* TOX_LOGGER */\n            setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));\n\n        LOGGER_DEBUG(res < 0 ? \"Failed to activate local multicast membership. (%u, %s)\" :\n                     \"Local multicast group FF02::1 joined successfully\", errno, strerror(errno) );\n    }\n\n    /* a hanging program or a different user might block the standard port;\n     * as long as it isn't a parameter coming from the commandline,\n     * try a few ports after it, to see if we can find a \"free\" one\n     *\n     * if we go on without binding, the first sendto() automatically binds to\n     * a free port chosen by the system (i.e. anything from 1024 to 65535)\n     *\n     * returning NULL after bind fails has both advantages and disadvantages:\n     * advantage:\n     *   we can rely on getting the port in the range 33445..33450, which\n     *   enables us to tell joe user to open their firewall to a small range\n     *\n     * disadvantage:\n     *   some clients might not test return of tox_new(), blindly assuming that\n     *   it worked ok (which it did previously without a successful bind)\n     */\n    uint16_t port_to_try = port_from;\n    *portptr = htons(port_to_try);\n    int tries;\n\n    for (tries = port_from; tries <= port_to; tries++) {\n        int res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);\n\n        if (!res) {\n            temp->port = *portptr;\n\n            LOGGER_DEBUG(\"Bound successfully to %s:%u\", ip_ntoa(&ip), ntohs(temp->port));\n\n            /* errno isn't reset on success, only set on failure, the failed\n             * binds with parallel clients yield a -EPERM to the outside if\n             * errno isn't cleared here */\n            if (tries > 0)\n                errno = 0;\n\n            if (error)\n                *error = 0;\n\n            return temp;\n        }\n\n        port_to_try++;\n\n        if (port_to_try > port_to)\n            port_to_try = port_from;\n\n        *portptr = htons(port_to_try);\n    }\n\n    LOGGER_ERROR(\"Failed to bind socket: %u, %s IP: %s port_from: %u port_to: %u\", errno, strerror(errno),\n                 ip_ntoa(&ip), port_from, port_to);\n\n    kill_networking(temp);\n\n    if (error)\n        *error = 1;\n\n    return NULL;\n}\n\n/* Function to cleanup networking stuff. */\nvoid kill_networking(Networking_Core *net)\n{\n    if (!net)\n        return;\n\n    if (net->family != 0) /* Socket not initialized */\n        kill_sock(net->sock);\n\n    free(net);\n    return;\n}\n\n\n/* ip_equal\n *  compares two IPAny structures\n *  unset means unequal\n *\n * returns 0 when not equal or when uninitialized\n */\nint ip_equal(const IP *a, const IP *b)\n{\n    if (!a || !b)\n        return 0;\n\n    /* same family */\n    if (a->family == b->family) {\n        if (a->family == AF_INET)\n            return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);\n        else if (a->family == AF_INET6)\n            return a->ip6.uint64[0] == b->ip6.uint64[0] && a->ip6.uint64[1] == b->ip6.uint64[1];\n        else\n            return 0;\n    }\n\n    /* different family: check on the IPv6 one if it is the IPv4 one embedded */\n    if ((a->family == AF_INET) && (b->family == AF_INET6)) {\n        if (IPV6_IPV4_IN_V6(b->ip6))\n            return (a->ip4.in_addr.s_addr == b->ip6.uint32[3]);\n    } else if ((a->family == AF_INET6)  && (b->family == AF_INET)) {\n        if (IPV6_IPV4_IN_V6(a->ip6))\n            return (a->ip6.uint32[3] == b->ip4.in_addr.s_addr);\n    }\n\n    return 0;\n}\n\n/* ipport_equal\n *  compares two IPAny_Port structures\n *  unset means unequal\n *\n * returns 0 when not equal or when uninitialized\n */\nint ipport_equal(const IP_Port *a, const IP_Port *b)\n{\n    if (!a || !b)\n        return 0;\n\n    if (!a->port || (a->port != b->port))\n        return 0;\n\n    return ip_equal(&a->ip, &b->ip);\n}\n\n/* nulls out ip */\nvoid ip_reset(IP *ip)\n{\n    if (!ip)\n        return;\n\n    memset(ip, 0, sizeof(IP));\n}\n\n/* nulls out ip, sets family according to flag */\nvoid ip_init(IP *ip, uint8_t ipv6enabled)\n{\n    if (!ip)\n        return;\n\n    memset(ip, 0, sizeof(IP));\n    ip->family = ipv6enabled ? AF_INET6 : AF_INET;\n}\n\n/* checks if ip is valid */\nint ip_isset(const IP *ip)\n{\n    if (!ip)\n        return 0;\n\n    return (ip->family != 0);\n}\n\n/* checks if ip is valid */\nint ipport_isset(const IP_Port *ipport)\n{\n    if (!ipport)\n        return 0;\n\n    if (!ipport->port)\n        return 0;\n\n    return ip_isset(&ipport->ip);\n}\n\n/* copies an ip structure (careful about direction!) */\nvoid ip_copy(IP *target, const IP *source)\n{\n    if (!source || !target)\n        return;\n\n    memcpy(target, source, sizeof(IP));\n}\n\n/* copies an ip_port structure (careful about direction!) */\nvoid ipport_copy(IP_Port *target, const IP_Port *source)\n{\n    if (!source || !target)\n        return;\n\n    memcpy(target, source, sizeof(IP_Port));\n}\n\n/* ip_ntoa\n *   converts ip into a string\n *   uses a static buffer, so mustn't used multiple times in the same output\n *\n *   IPv6 addresses are enclosed into square brackets, i.e. \"[IPv6]\"\n *   writes error message into the buffer on error\n */\n/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */\nstatic char addresstext[96]; // FIXME magic number. Why not INET6_ADDRSTRLEN ?\nconst char *ip_ntoa(const IP *ip)\n{\n    if (ip) {\n        if (ip->family == AF_INET) {\n            /* returns standard quad-dotted notation */\n            struct in_addr *addr = (struct in_addr *)&ip->ip4;\n\n            addresstext[0] = 0;\n            inet_ntop(ip->family, addr, addresstext, sizeof(addresstext));\n        } else if (ip->family == AF_INET6) {\n            /* returns hex-groups enclosed into square brackets */\n            struct in6_addr *addr = (struct in6_addr *)&ip->ip6;\n\n            addresstext[0] = '[';\n            inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3);\n            size_t len = strlen(addresstext);\n            addresstext[len] = ']';\n            addresstext[len + 1] = 0;\n        } else\n            snprintf(addresstext, sizeof(addresstext), \"(IP invalid, family %u)\", ip->family);\n    } else\n        snprintf(addresstext, sizeof(addresstext), \"(IP invalid: NULL)\");\n\n    /* brute force protection against lacking termination */\n    addresstext[sizeof(addresstext) - 1] = 0;\n    return addresstext;\n}\n\n/*\n * ip_parse_addr\n *  parses IP structure into an address string\n *\n * input\n *  ip: ip of AF_INET or AF_INET6 families\n *  length: length of the address buffer\n *          Must be at least INET_ADDRSTRLEN for AF_INET\n *          and INET6_ADDRSTRLEN for AF_INET6\n *\n * output\n *  address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)\n *\n * returns 1 on success, 0 on failure\n */\nint ip_parse_addr(const IP *ip, char *address, size_t length)\n{\n    if (!address || !ip) {\n        return 0;\n    }\n\n    if (ip->family == AF_INET) {\n        struct in_addr *addr = (struct in_addr *)&ip->ip4;\n        return inet_ntop(ip->family, addr, address, length) != NULL;\n    } else if (ip->family == AF_INET6) {\n        struct in6_addr *addr = (struct in6_addr *)&ip->ip6;\n        return inet_ntop(ip->family, addr, address, length) != NULL;\n    }\n\n    return 0;\n}\n\n/*\n * addr_parse_ip\n *  directly parses the input into an IP structure\n *  tries IPv4 first, then IPv6\n *\n * input\n *  address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)\n *\n * output\n *  IP: family and the value is set on success\n *\n * returns 1 on success, 0 on failure\n */\nint addr_parse_ip(const char *address, IP *to)\n{\n    if (!address || !to)\n        return 0;\n\n    struct in_addr addr4;\n\n    if (1 == inet_pton(AF_INET, address, &addr4)) {\n        to->family = AF_INET;\n        to->ip4.in_addr = addr4;\n        return 1;\n    }\n\n    struct in6_addr addr6;\n\n    if (1 == inet_pton(AF_INET6, address, &addr6)) {\n        to->family = AF_INET6;\n        to->ip6.in6_addr = addr6;\n        return 1;\n    }\n\n    return 0;\n}\n\n/*\n * addr_resolve():\n *  uses getaddrinfo to resolve an address into an IP address\n *  uses the first IPv4/IPv6 addresses returned by getaddrinfo\n *\n * input\n *  address: a hostname (or something parseable to an IP address)\n *  to: to.family MUST be initialized, either set to a specific IP version\n *     (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both\n *     IP versions are acceptable\n *  extra can be NULL and is only set in special circumstances, see returns\n *\n * returns in *to a valid IPAny (v4/v6),\n *     prefers v6 if ip.family was AF_UNSPEC and both available\n * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6\n * returns 0 on failure, TOX_ADDR_RESOLVE_* on success.\n */\nint addr_resolve(const char *address, IP *to, IP *extra)\n{\n    if (!address || !to)\n        return 0;\n\n    sa_family_t family = to->family;\n\n    struct addrinfo *server = NULL;\n    struct addrinfo *walker = NULL;\n    struct addrinfo  hints;\n    int rc;\n    int result = 0;\n    int done = 0;\n\n    memset(&hints, 0, sizeof(hints));\n    hints.ai_family   = family;\n    hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.\n\n    if (networking_at_startup() != 0)\n        return 0;\n\n    rc = getaddrinfo(address, NULL, &hints, &server);\n\n    // Lookup failed.\n    if (rc != 0) {\n        return 0;\n    }\n\n    IP ip4;\n    ip_init(&ip4, 0); // ipv6enabled = 0\n    IP ip6;\n    ip_init(&ip6, 1); // ipv6enabled = 1\n\n    for (walker = server; (walker != NULL) && !done; walker = walker->ai_next) {\n        switch (walker->ai_family) {\n            case AF_INET:\n                if (walker->ai_family == family) { /* AF_INET requested, done */\n                    struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;\n                    to->ip4.in_addr = addr->sin_addr;\n                    result = TOX_ADDR_RESOLVE_INET;\n                    done = 1;\n                } else if (!(result & TOX_ADDR_RESOLVE_INET)) { /* AF_UNSPEC requested, store away */\n                    struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;\n                    ip4.ip4.in_addr = addr->sin_addr;\n                    result |= TOX_ADDR_RESOLVE_INET;\n                }\n\n                break; /* switch */\n\n            case AF_INET6:\n                if (walker->ai_family == family) { /* AF_INET6 requested, done */\n                    if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {\n                        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;\n                        to->ip6.in6_addr = addr->sin6_addr;\n                        result = TOX_ADDR_RESOLVE_INET6;\n                        done = 1;\n                    }\n                } else if (!(result & TOX_ADDR_RESOLVE_INET6)) { /* AF_UNSPEC requested, store away */\n                    if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {\n                        struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;\n                        ip6.ip6.in6_addr = addr->sin6_addr;\n                        result |= TOX_ADDR_RESOLVE_INET6;\n                    }\n                }\n\n                break; /* switch */\n        }\n    }\n\n    if (family == AF_UNSPEC) {\n        if (result & TOX_ADDR_RESOLVE_INET6) {\n            ip_copy(to, &ip6);\n\n            if ((result & TOX_ADDR_RESOLVE_INET) && (extra != NULL)) {\n                ip_copy(extra, &ip4);\n            }\n        } else if (result & TOX_ADDR_RESOLVE_INET) {\n            ip_copy(to, &ip4);\n        } else {\n            result = 0;\n        }\n    }\n\n    freeaddrinfo(server);\n    return result;\n}\n\n/*\n * addr_resolve_or_parse_ip\n *  resolves string into an IP address\n *\n *  address: a hostname (or something parseable to an IP address)\n *  to: to.family MUST be initialized, either set to a specific IP version\n *     (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both\n *     IP versions are acceptable\n *  extra can be NULL and is only set in special circumstances, see returns\n *\n *  returns in *tro a matching address (IPv6 or IPv4)\n *  returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC\n *  returns 1 on success\n *  returns 0 on failure\n */\nint addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra)\n{\n    if (!addr_resolve(address, to, extra))\n        if (!addr_parse_ip(address, to))\n            return 0;\n\n    return 1;\n}\n"
  },
  {
    "path": "toxcore/network.h",
    "content": "/* network.h\n *\n * Datatypes, functions and includes for the core networking.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef NETWORK_H\n#define NETWORK_H\n\n#ifdef PLAN9\n#include <u.h> //Plan 9 requires this is imported first\n#include <libc.h>\n#endif\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n#include <time.h>\n\n#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) /* Put win32 includes here */\n#ifndef WINVER\n//Windows XP\n#define WINVER 0x0501\n#endif\n#include <winsock2.h>\n#include <windows.h>\n#include <ws2tcpip.h>\n\n#ifndef IPV6_V6ONLY\n#define IPV6_V6ONLY 27\n#endif\n\ntypedef unsigned int sock_t;\n/* sa_family_t is the sockaddr_in / sockaddr_in6 family field */\ntypedef short sa_family_t;\n\n#ifndef EWOULDBLOCK\n#define EWOULDBLOCK WSAEWOULDBLOCK\n#endif\n\n#else // Linux includes\n\n#include <fcntl.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <errno.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <netdb.h>\n#include <unistd.h>\n\ntypedef int sock_t;\n\n#endif\n\n#if defined(__AIX__)\n#   define _XOPEN_SOURCE 1\n#endif\n\n#if defined(__sun__)\n#define __EXTENSIONS__ 1 // SunOS!\n#if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__)\n//Nothing needed\n#else\n#define __MAKECONTEXT_V2_SOURCE 1\n#endif\n#endif\n\n#ifndef IPV6_ADD_MEMBERSHIP\n#ifdef  IPV6_JOIN_GROUP\n#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP\n#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP\n#endif\n#endif\n\n#define MAX_UDP_PACKET_SIZE 2048\n\n#define NET_PACKET_PING_REQUEST    0   /* Ping request packet ID. */\n#define NET_PACKET_PING_RESPONSE   1   /* Ping response packet ID. */\n#define NET_PACKET_GET_NODES       2   /* Get nodes request packet ID. */\n#define NET_PACKET_SEND_NODES_IPV6 4   /* Send nodes response packet ID for other addresses. */\n#define NET_PACKET_COOKIE_REQUEST  24  /* Cookie request packet */\n#define NET_PACKET_COOKIE_RESPONSE 25  /* Cookie response packet */\n#define NET_PACKET_CRYPTO_HS       26  /* Crypto handshake packet */\n#define NET_PACKET_CRYPTO_DATA     27  /* Crypto data packet */\n#define NET_PACKET_CRYPTO          32  /* Encrypted data packet ID. */\n#define NET_PACKET_LAN_DISCOVERY   33  /* LAN discovery packet ID. */\n\n/* See:  docs/Prevent_Tracking.txt and onion.{c, h} */\n#define NET_PACKET_ONION_SEND_INITIAL 128\n#define NET_PACKET_ONION_SEND_1 129\n#define NET_PACKET_ONION_SEND_2 130\n\n#define NET_PACKET_ANNOUNCE_REQUEST 131\n#define NET_PACKET_ANNOUNCE_RESPONSE 132\n#define NET_PACKET_ONION_DATA_REQUEST 133\n#define NET_PACKET_ONION_DATA_RESPONSE 134\n\n#define NET_PACKET_ONION_RECV_3 140\n#define NET_PACKET_ONION_RECV_2 141\n#define NET_PACKET_ONION_RECV_1 142\n\n/* Only used for bootstrap nodes */\n#define BOOTSTRAP_INFO_PACKET_ID 240\n\n\n#define TOX_PORTRANGE_FROM 33445\n#define TOX_PORTRANGE_TO   33545\n#define TOX_PORT_DEFAULT   TOX_PORTRANGE_FROM\n\n/* TCP related */\n#define TCP_ONION_FAMILY (AF_INET6 + 1)\n#define TCP_INET (AF_INET6 + 2)\n#define TCP_INET6 (AF_INET6 + 3)\n#define TCP_FAMILY (AF_INET6 + 4)\n\ntypedef union {\n    uint8_t uint8[4];\n    uint16_t uint16[2];\n    uint32_t uint32;\n    struct in_addr in_addr;\n}\nIP4;\n\ntypedef union {\n    uint8_t uint8[16];\n    uint16_t uint16[8];\n    uint32_t uint32[4];\n    uint64_t uint64[2];\n    struct in6_addr in6_addr;\n}\nIP6;\n\ntypedef struct {\n    uint8_t family;\n    union {\n        IP4 ip4;\n        IP6 ip6;\n    };\n}\nIP;\n\ntypedef struct {\n    IP ip;\n    uint16_t port;\n}\nIP_Port;\n\n/* Does the IP6 struct a contain an IPv4 address in an IPv6 one? */\n#define IPV6_IPV4_IN_V6(a) ((a.uint64[0] == 0) && (a.uint32[2] == htonl (0xffff)))\n\n#define SIZE_IP4 4\n#define SIZE_IP6 16\n#define SIZE_IP (1 + SIZE_IP6)\n#define SIZE_PORT 2\n#define SIZE_IPPORT (SIZE_IP + SIZE_PORT)\n\n#define TOX_ENABLE_IPV6_DEFAULT 1\n\n/* addr_resolve return values */\n#define TOX_ADDR_RESOLVE_INET  1\n#define TOX_ADDR_RESOLVE_INET6 2\n\n/* ip_ntoa\n *   converts ip into a string\n *   uses a static buffer, so mustn't used multiple times in the same output\n *\n *   IPv6 addresses are enclosed into square brackets, i.e. \"[IPv6]\"\n *   writes error message into the buffer on error\n */\nconst char *ip_ntoa(const IP *ip);\n\n/*\n * ip_parse_addr\n *  parses IP structure into an address string\n *\n * input\n *  ip: ip of AF_INET or AF_INET6 families\n *  length: length of the address buffer\n *          Must be at least INET_ADDRSTRLEN for AF_INET\n *          and INET6_ADDRSTRLEN for AF_INET6\n *\n * output\n *  address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)\n *\n * returns 1 on success, 0 on failure\n */\nint ip_parse_addr(const IP *ip, char *address, size_t length);\n\n/*\n * addr_parse_ip\n *  directly parses the input into an IP structure\n *  tries IPv4 first, then IPv6\n *\n * input\n *  address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)\n *\n * output\n *  IP: family and the value is set on success\n *\n * returns 1 on success, 0 on failure\n */\nint addr_parse_ip(const char *address, IP *to);\n\n/* ip_equal\n *  compares two IPAny structures\n *  unset means unequal\n *\n * returns 0 when not equal or when uninitialized\n */\nint ip_equal(const IP *a, const IP *b);\n\n/* ipport_equal\n *  compares two IPAny_Port structures\n *  unset means unequal\n *\n * returns 0 when not equal or when uninitialized\n */\nint ipport_equal(const IP_Port *a, const IP_Port *b);\n\n/* nulls out ip */\nvoid ip_reset(IP *ip);\n/* nulls out ip, sets family according to flag */\nvoid ip_init(IP *ip, uint8_t ipv6enabled);\n/* checks if ip is valid */\nint ip_isset(const IP *ip);\n/* checks if ip is valid */\nint ipport_isset(const IP_Port *ipport);\n/* copies an ip structure */\nvoid ip_copy(IP *target, const IP *source);\n/* copies an ip_port structure */\nvoid ipport_copy(IP_Port *target, const IP_Port *source);\n\n/*\n * addr_resolve():\n *  uses getaddrinfo to resolve an address into an IP address\n *  uses the first IPv4/IPv6 addresses returned by getaddrinfo\n *\n * input\n *  address: a hostname (or something parseable to an IP address)\n *  to: to.family MUST be initialized, either set to a specific IP version\n *     (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both\n *     IP versions are acceptable\n *  extra can be NULL and is only set in special circumstances, see returns\n *\n * returns in *to a valid IPAny (v4/v6),\n *     prefers v6 if ip.family was AF_UNSPEC and both available\n * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is AF_INET6\n * returns 0 on failure\n */\nint addr_resolve(const char *address, IP *to, IP *extra);\n\n/*\n * addr_resolve_or_parse_ip\n *  resolves string into an IP address\n *\n *  address: a hostname (or something parseable to an IP address)\n *  to: to.family MUST be initialized, either set to a specific IP version\n *     (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both\n *     IP versions are acceptable\n *  extra can be NULL and is only set in special circumstances, see returns\n *\n *  returns in *tro a matching address (IPv6 or IPv4)\n *  returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC\n *  returns 1 on success\n *  returns 0 on failure\n */\nint addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra);\n\n/* Function to receive data, ip and port of sender is put into ip_port.\n * Packet data is put into data.\n * Packet length is put into length.\n */\ntypedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint16_t len);\n\ntypedef struct {\n    packet_handler_callback function;\n    void *object;\n} Packet_Handles;\n\ntypedef struct {\n    Packet_Handles packethandlers[256];\n\n    sa_family_t family;\n    uint16_t port;\n    /* Our UDP socket. */\n    sock_t sock;\n} Networking_Core;\n\n/* Run this before creating sockets.\n *\n * return 0 on success\n * return -1 on failure\n */\nint networking_at_startup(void);\n\n/* Check if socket is valid.\n *\n * return 1 if valid\n * return 0 if not valid\n */\nint sock_valid(sock_t sock);\n\n/* Close the socket.\n */\nvoid kill_sock(sock_t sock);\n\n/* Set socket as nonblocking\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_nonblock(sock_t sock);\n\n/* Set socket to not emit SIGPIPE\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_nosigpipe(sock_t sock);\n\n/* Enable SO_REUSEADDR on socket.\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_reuseaddr(sock_t sock);\n\n/* Set socket to dual (IPv4 + IPv6 socket)\n *\n * return 1 on success\n * return 0 on failure\n */\nint set_socket_dualstack(sock_t sock);\n\n/* return current monotonic time in milliseconds (ms). */\nuint64_t current_time_monotonic(void);\n\n/* Basic network functions: */\n\n/* Function to send packet(data) of length length to ip_port. */\nint sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length);\n\n/* Function to call when packet beginning with byte is received. */\nvoid networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object);\n\n/* Call this several times a second. */\nvoid networking_poll(Networking_Core *net);\n\n/* Initialize networking.\n * bind to ip and port.\n * ip must be in network order EX: 127.0.0.1 = (7F000001).\n * port is in host byte order (this means don't worry about it).\n *\n * return Networking_Core object if no problems\n * return NULL if there are problems.\n *\n * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other.\n */\nNetworking_Core *new_networking(IP ip, uint16_t port);\nNetworking_Core *new_networking_ex(IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error);\n\n/* Function to cleanup networking stuff (doesn't do much right now). */\nvoid kill_networking(Networking_Core *net);\n\n#endif\n"
  },
  {
    "path": "toxcore/onion.c",
    "content": "/*\n* onion.c -- Implementation of the onion part of docs/Prevent_Tracking.txt\n*\n*  Copyright (C) 2013 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"onion.h\"\n#include \"util.h\"\n\n#define RETURN_1 ONION_RETURN_1\n#define RETURN_2 ONION_RETURN_2\n#define RETURN_3 ONION_RETURN_3\n\n#define SEND_BASE ONION_SEND_BASE\n#define SEND_3 ONION_SEND_3\n#define SEND_2 ONION_SEND_2\n#define SEND_1 ONION_SEND_1\n\n/* Change symmetric keys every 2 hours to make paths expire eventually. */\n#define KEY_REFRESH_INTERVAL (2 * 60 * 60)\nstatic void change_symmetric_key(Onion *onion)\n{\n    if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) {\n        new_symmetric_key(onion->secret_symmetric_key);\n        onion->timestamp = unix_time();\n    }\n}\n\n/* packing and unpacking functions */\nstatic void ip_pack(uint8_t *data, IP source)\n{\n    to_net_family(&source);\n\n    data[0] = source.family;\n\n    if (source.family == TOX_AF_INET || source.family == TOX_TCP_INET) {\n        memset(data + 1, 0, SIZE_IP6);\n        memcpy(data + 1, source.ip4.uint8, SIZE_IP4);\n    } else {\n        memcpy(data + 1, source.ip6.uint8, SIZE_IP6);\n    }\n}\n\n/* return 0 on success, -1 on failure. */\nstatic int ip_unpack(IP *target, const uint8_t *data, unsigned int data_size, _Bool disable_family_check)\n{\n    if (data_size < (1 + SIZE_IP6))\n        return -1;\n\n    target->family = data[0];\n\n    if (target->family == TOX_AF_INET || target->family == TOX_TCP_INET) {\n        memcpy(target->ip4.uint8, data + 1, SIZE_IP4);\n    } else {\n        memcpy(target->ip6.uint8, data + 1, SIZE_IP6);\n    }\n\n    if (!disable_family_check) {\n        return to_host_family(target);\n    } else {\n        to_host_family(target);\n        return 0;\n    }\n}\n\nstatic void ipport_pack(uint8_t *data, const IP_Port *source)\n{\n    ip_pack(data, source->ip);\n    memcpy(data + SIZE_IP, &source->port, SIZE_PORT);\n}\n\n/* return 0 on success, -1 on failure. */\nstatic int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data_size, _Bool disable_family_check)\n{\n    if (data_size < (SIZE_IP + SIZE_PORT))\n        return -1;\n\n    if (ip_unpack(&target->ip, data, data_size, disable_family_check) == -1)\n        return -1;\n\n    memcpy(&target->port, data + SIZE_IP, SIZE_PORT);\n    return 0;\n}\n\n\n/* Create a new onion path.\n *\n * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes)\n *\n * new_path must be an empty memory location of atleast Onion_Path size.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes)\n{\n    if (!new_path || !nodes)\n        return -1;\n\n    encrypt_precompute(nodes[0].public_key, dht->self_secret_key, new_path->shared_key1);\n    memcpy(new_path->public_key1, dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n\n    uint8_t random_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t random_secret_key[crypto_box_SECRETKEYBYTES];\n\n    crypto_box_keypair(random_public_key, random_secret_key);\n    encrypt_precompute(nodes[1].public_key, random_secret_key, new_path->shared_key2);\n    memcpy(new_path->public_key2, random_public_key, crypto_box_PUBLICKEYBYTES);\n\n    crypto_box_keypair(random_public_key, random_secret_key);\n    encrypt_precompute(nodes[2].public_key, random_secret_key, new_path->shared_key3);\n    memcpy(new_path->public_key3, random_public_key, crypto_box_PUBLICKEYBYTES);\n\n    new_path->ip_port1 = nodes[0].ip_port;\n    new_path->ip_port2 = nodes[1].ip_port;\n    new_path->ip_port3 = nodes[2].ip_port;\n\n    memcpy(new_path->node_public_key1, nodes[0].public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(new_path->node_public_key2, nodes[1].public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(new_path->node_public_key3, nodes[2].public_key, crypto_box_PUBLICKEYBYTES);\n\n    return 0;\n}\n\n/* Dump nodes in onion path to nodes of length num_nodes;\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path)\n{\n    if (num_nodes < ONION_PATH_LENGTH)\n        return -1;\n\n    nodes[0].ip_port = path->ip_port1;\n    nodes[1].ip_port = path->ip_port2;\n    nodes[2].ip_port = path->ip_port3;\n\n    memcpy(nodes[0].public_key, path->node_public_key1, crypto_box_PUBLICKEYBYTES);\n    memcpy(nodes[1].public_key, path->node_public_key2, crypto_box_PUBLICKEYBYTES);\n    memcpy(nodes[2].public_key, path->node_public_key3, crypto_box_PUBLICKEYBYTES);\n    return 0;\n}\n\n/* Create a onion packet.\n *\n * Use Onion_Path path to create packet for data of length to dest.\n * Maximum length of data is ONION_MAX_DATA_SIZE.\n * packet should be at least ONION_MAX_PACKET_SIZE big.\n *\n * return -1 on failure.\n * return length of created packet on success.\n */\nint create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest,\n                        const uint8_t *data, uint16_t length)\n{\n    if (1 + length + SEND_1 > max_packet_length || length == 0)\n        return -1;\n\n    uint8_t step1[SIZE_IPPORT + length];\n\n    ipport_pack(step1, &dest);\n    memcpy(step1 + SIZE_IPPORT, data, length);\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    random_nonce(nonce);\n\n    uint8_t step2[SIZE_IPPORT + SEND_BASE + length];\n    ipport_pack(step2, &path->ip_port3);\n    memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES);\n\n    int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1),\n                                     step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES);\n\n    if (len != SIZE_IPPORT + length + crypto_box_MACBYTES)\n        return -1;\n\n    uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length];\n    ipport_pack(step3, &path->ip_port2);\n    memcpy(step3 + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES);\n    len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2),\n                                 step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES);\n\n    if (len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES)\n        return -1;\n\n    packet[0] = NET_PACKET_ONION_SEND_INITIAL;\n    memcpy(packet + 1, nonce, crypto_box_NONCEBYTES);\n    memcpy(packet + 1 + crypto_box_NONCEBYTES, path->public_key1, crypto_box_PUBLICKEYBYTES);\n\n    len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3),\n                                 packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES);\n\n    if (len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES)\n        return -1;\n\n    return 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len;\n}\n\n/* Create a onion packet to be sent over tcp.\n *\n * Use Onion_Path path to create packet for data of length to dest.\n * Maximum length of data is ONION_MAX_DATA_SIZE.\n * packet should be at least ONION_MAX_PACKET_SIZE big.\n *\n * return -1 on failure.\n * return length of created packet on success.\n */\nint create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest,\n                            const uint8_t *data, uint16_t length)\n{\n    if (crypto_box_NONCEBYTES + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0)\n        return -1;\n\n    uint8_t step1[SIZE_IPPORT + length];\n\n    ipport_pack(step1, &dest);\n    memcpy(step1 + SIZE_IPPORT, data, length);\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    random_nonce(nonce);\n\n    uint8_t step2[SIZE_IPPORT + SEND_BASE + length];\n    ipport_pack(step2, &path->ip_port3);\n    memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES);\n\n    int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1),\n                                     step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES);\n\n    if (len != SIZE_IPPORT + length + crypto_box_MACBYTES)\n        return -1;\n\n    ipport_pack(packet + crypto_box_NONCEBYTES, &path->ip_port2);\n    memcpy(packet + crypto_box_NONCEBYTES + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES);\n    len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2),\n                                 packet + crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES);\n\n    if (len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES)\n        return -1;\n\n    memcpy(packet, nonce, crypto_box_NONCEBYTES);\n\n    return crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES + len;\n}\n\n/* Create and send a onion packet.\n *\n * Use Onion_Path path to send data of length to dest.\n * Maximum length of data is ONION_MAX_DATA_SIZE.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length)\n{\n    uint8_t packet[ONION_MAX_PACKET_SIZE];\n    int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length);\n\n    if (len == -1)\n        return -1;\n\n    if (sendpacket(net, path->ip_port1, packet, len) != len)\n        return -1;\n\n    return 0;\n}\n\n/* Create and send a onion response sent initially to dest with.\n * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret)\n{\n    if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0)\n        return -1;\n\n    uint8_t packet[1 + RETURN_3 + length];\n    packet[0] = NET_PACKET_ONION_RECV_3;\n    memcpy(packet + 1, ret, RETURN_3);\n    memcpy(packet + 1 + RETURN_3, data, length);\n\n    if ((uint32_t)sendpacket(net, dest, packet, sizeof(packet)) != sizeof(packet))\n        return -1;\n\n    return 0;\n}\n\nstatic int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    if (length <= 1 + SEND_1)\n        return 1;\n\n    change_symmetric_key(onion);\n\n    uint8_t plain[ONION_MAX_PACKET_SIZE];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES);\n    int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,\n                                     length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain);\n\n    if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES))\n        return 1;\n\n    return onion_send_1(onion, plain, len, source, packet + 1);\n}\n\nint onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce)\n{\n    if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + crypto_box_NONCEBYTES + ONION_RETURN_1))\n        return 1;\n\n    if (len <= SIZE_IPPORT + SEND_BASE * 2)\n        return 1;\n\n    IP_Port send_to;\n\n    if (ipport_unpack(&send_to, plain, len, 0) == -1)\n        return 1;\n\n    uint8_t ip_port[SIZE_IPPORT];\n    ipport_pack(ip_port, &source);\n\n    uint8_t data[ONION_MAX_PACKET_SIZE];\n    data[0] = NET_PACKET_ONION_SEND_1;\n    memcpy(data + 1, nonce, crypto_box_NONCEBYTES);\n    memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT);\n    uint16_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT);\n    uint8_t *ret_part = data + data_len;\n    new_nonce(ret_part);\n    len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT,\n                                 ret_part + crypto_box_NONCEBYTES);\n\n    if (len != SIZE_IPPORT + crypto_box_MACBYTES)\n        return 1;\n\n    data_len += crypto_box_NONCEBYTES + len;\n\n    if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)\n        return 1;\n\n    return 0;\n}\n\nstatic int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    if (length <= 1 + SEND_2)\n        return 1;\n\n    change_symmetric_key(onion);\n\n    uint8_t plain[ONION_MAX_PACKET_SIZE];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES);\n    int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,\n                                     length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain);\n\n    if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES))\n        return 1;\n\n    IP_Port send_to;\n\n    if (ipport_unpack(&send_to, plain, len, 0) == -1)\n        return 1;\n\n    uint8_t data[ONION_MAX_PACKET_SIZE];\n    data[0] = NET_PACKET_ONION_SEND_2;\n    memcpy(data + 1, packet + 1, crypto_box_NONCEBYTES);\n    memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT);\n    uint16_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT);\n    uint8_t *ret_part = data + data_len;\n    new_nonce(ret_part);\n    uint8_t ret_data[RETURN_1 + SIZE_IPPORT];\n    ipport_pack(ret_data, &source);\n    memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1);\n    len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data),\n                                 ret_part + crypto_box_NONCEBYTES);\n\n    if (len != RETURN_2 - crypto_box_NONCEBYTES)\n        return 1;\n\n    data_len += crypto_box_NONCEBYTES + len;\n\n    if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)\n        return 1;\n\n    return 0;\n}\n\nstatic int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    if (length <= 1 + SEND_3)\n        return 1;\n\n    change_symmetric_key(onion);\n\n    uint8_t plain[ONION_MAX_PACKET_SIZE];\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES);\n    int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,\n                                     length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain);\n\n    if (len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES))\n        return 1;\n\n    if (len <= SIZE_IPPORT) {\n        return 1;\n    }\n\n    if (plain[SIZE_IPPORT] != NET_PACKET_ANNOUNCE_REQUEST &&\n            plain[SIZE_IPPORT] != NET_PACKET_ONION_DATA_REQUEST) {\n        return 1;\n    }\n\n    IP_Port send_to;\n\n    if (ipport_unpack(&send_to, plain, len, 0) == -1)\n        return 1;\n\n    uint8_t data[ONION_MAX_PACKET_SIZE];\n    memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT);\n    uint16_t data_len = (len - SIZE_IPPORT);\n    uint8_t *ret_part = data + (len - SIZE_IPPORT);\n    new_nonce(ret_part);\n    uint8_t ret_data[RETURN_2 + SIZE_IPPORT];\n    ipport_pack(ret_data, &source);\n    memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2);\n    len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data),\n                                 ret_part + crypto_box_NONCEBYTES);\n\n    if (len != RETURN_3 - crypto_box_NONCEBYTES)\n        return 1;\n\n    data_len += RETURN_3;\n\n    if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)\n        return 1;\n\n    return 0;\n}\n\n\nstatic int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    if (length <= 1 + RETURN_3)\n        return 1;\n\n    if (packet[1 + RETURN_3] != NET_PACKET_ANNOUNCE_RESPONSE &&\n            packet[1 + RETURN_3] != NET_PACKET_ONION_DATA_RESPONSE) {\n        return 1;\n    }\n\n    change_symmetric_key(onion);\n\n    uint8_t plain[SIZE_IPPORT + RETURN_2];\n    int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,\n                                     SIZE_IPPORT + RETURN_2 + crypto_box_MACBYTES, plain);\n\n    if ((uint32_t)len != sizeof(plain))\n        return 1;\n\n    IP_Port send_to;\n\n    if (ipport_unpack(&send_to, plain, len, 0) == -1)\n        return 1;\n\n    uint8_t data[ONION_MAX_PACKET_SIZE];\n    data[0] = NET_PACKET_ONION_RECV_2;\n    memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2);\n    memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3));\n    uint16_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3));\n\n    if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)\n        return 1;\n\n    return 0;\n}\n\nstatic int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    if (length <= 1 + RETURN_2)\n        return 1;\n\n    if (packet[1 + RETURN_2] != NET_PACKET_ANNOUNCE_RESPONSE &&\n            packet[1 + RETURN_2] != NET_PACKET_ONION_DATA_RESPONSE) {\n        return 1;\n    }\n\n    change_symmetric_key(onion);\n\n    uint8_t plain[SIZE_IPPORT + RETURN_1];\n    int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,\n                                     SIZE_IPPORT + RETURN_1 + crypto_box_MACBYTES, plain);\n\n    if ((uint32_t)len != sizeof(plain))\n        return 1;\n\n    IP_Port send_to;\n\n    if (ipport_unpack(&send_to, plain, len, 0) == -1)\n        return 1;\n\n    uint8_t data[ONION_MAX_PACKET_SIZE];\n    data[0] = NET_PACKET_ONION_RECV_1;\n    memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1);\n    memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2));\n    uint16_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2));\n\n    if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)\n        return 1;\n\n    return 0;\n}\n\nstatic int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion *onion = object;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    if (length <= 1 + RETURN_1)\n        return 1;\n\n    if (packet[1 + RETURN_1] != NET_PACKET_ANNOUNCE_RESPONSE &&\n            packet[1 + RETURN_1] != NET_PACKET_ONION_DATA_RESPONSE) {\n        return 1;\n    }\n\n    change_symmetric_key(onion);\n\n    uint8_t plain[SIZE_IPPORT];\n    int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,\n                                     SIZE_IPPORT + crypto_box_MACBYTES, plain);\n\n    if ((uint32_t)len != SIZE_IPPORT)\n        return 1;\n\n    IP_Port send_to;\n\n    if (ipport_unpack(&send_to, plain, len, 1) == -1)\n        return 1;\n\n    uint16_t data_len = length - (1 + RETURN_1);\n\n    if (onion->recv_1_function && send_to.ip.family != AF_INET && send_to.ip.family != AF_INET6)\n        return onion->recv_1_function(onion->callback_object, send_to, packet + (1 + RETURN_1), data_len);\n\n    if ((uint32_t)sendpacket(onion->net, send_to, packet + (1 + RETURN_1), data_len) != data_len)\n        return 1;\n\n    return 0;\n}\n\nvoid set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), void *object)\n{\n    onion->recv_1_function = function;\n    onion->callback_object = object;\n}\n\nOnion *new_onion(DHT *dht)\n{\n    if (dht == NULL)\n        return NULL;\n\n    Onion *onion = calloc(1, sizeof(Onion));\n\n    if (onion == NULL)\n        return NULL;\n\n    onion->dht = dht;\n    onion->net = dht->net;\n    new_symmetric_key(onion->secret_symmetric_key);\n    onion->timestamp = unix_time();\n\n    networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion);\n\n    networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, &handle_recv_3, onion);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, &handle_recv_2, onion);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, &handle_recv_1, onion);\n\n    return onion;\n}\n\nvoid kill_onion(Onion *onion)\n{\n    if (onion == NULL)\n        return;\n\n    networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, NULL, NULL);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, NULL, NULL);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, NULL, NULL);\n\n    networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, NULL, NULL);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, NULL, NULL);\n    networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, NULL, NULL);\n\n    free(onion);\n}\n"
  },
  {
    "path": "toxcore/onion.h",
    "content": "/*\n* onion.h -- Implementation of the onion part of docs/Prevent_Tracking.txt\n*\n*  Copyright (C) 2013 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n#ifndef ONION_H\n#define ONION_H\n\n#include \"DHT.h\"\n\ntypedef struct {\n    DHT     *dht;\n    Networking_Core *net;\n    uint8_t secret_symmetric_key[crypto_box_KEYBYTES];\n    uint64_t timestamp;\n\n    Shared_Keys shared_keys_1;\n    Shared_Keys shared_keys_2;\n    Shared_Keys shared_keys_3;\n\n    int (*recv_1_function)(void *, IP_Port, const uint8_t *, uint16_t);\n    void *callback_object;\n} Onion;\n\n#define ONION_MAX_PACKET_SIZE 1400\n\n#define ONION_RETURN_1 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES)\n#define ONION_RETURN_2 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES + ONION_RETURN_1)\n#define ONION_RETURN_3 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES + ONION_RETURN_2)\n\n#define ONION_SEND_BASE (crypto_box_PUBLICKEYBYTES + SIZE_IPPORT + crypto_box_MACBYTES)\n#define ONION_SEND_3 (crypto_box_NONCEBYTES + ONION_SEND_BASE + ONION_RETURN_2)\n#define ONION_SEND_2 (crypto_box_NONCEBYTES + ONION_SEND_BASE*2 + ONION_RETURN_1)\n#define ONION_SEND_1 (crypto_box_NONCEBYTES + ONION_SEND_BASE*3)\n\n#define ONION_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (ONION_SEND_1 + 1))\n#define ONION_RESPONSE_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (1 + ONION_RETURN_3))\n\n#define ONION_PATH_LENGTH 3\n\ntypedef struct {\n    uint8_t shared_key1[crypto_box_BEFORENMBYTES];\n    uint8_t shared_key2[crypto_box_BEFORENMBYTES];\n    uint8_t shared_key3[crypto_box_BEFORENMBYTES];\n\n    uint8_t public_key1[crypto_box_PUBLICKEYBYTES];\n    uint8_t public_key2[crypto_box_PUBLICKEYBYTES];\n    uint8_t public_key3[crypto_box_PUBLICKEYBYTES];\n\n    IP_Port     ip_port1;\n    uint8_t     node_public_key1[crypto_box_PUBLICKEYBYTES];\n\n    IP_Port     ip_port2;\n    uint8_t     node_public_key2[crypto_box_PUBLICKEYBYTES];\n\n    IP_Port     ip_port3;\n    uint8_t     node_public_key3[crypto_box_PUBLICKEYBYTES];\n\n    uint32_t path_num;\n} Onion_Path;\n\n/* Create a new onion path.\n *\n * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes)\n *\n * new_path must be an empty memory location of atleast Onion_Path size.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes);\n\n/* Dump nodes in onion path to nodes of length num_nodes;\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path);\n\n/* Create a onion packet.\n *\n * Use Onion_Path path to create packet for data of length to dest.\n * Maximum length of data is ONION_MAX_DATA_SIZE.\n * packet should be at least ONION_MAX_PACKET_SIZE big.\n *\n * return -1 on failure.\n * return length of created packet on success.\n */\nint create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest,\n                        const uint8_t *data, uint16_t length);\n\n\n/* Create a onion packet to be sent over tcp.\n *\n * Use Onion_Path path to create packet for data of length to dest.\n * Maximum length of data is ONION_MAX_DATA_SIZE.\n * packet should be at least ONION_MAX_PACKET_SIZE big.\n *\n * return -1 on failure.\n * return length of created packet on success.\n */\nint create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest,\n                            const uint8_t *data, uint16_t length);\n\n/* Create and send a onion packet.\n *\n * Use Onion_Path path to send data of length to dest.\n * Maximum length of data is ONION_MAX_DATA_SIZE.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length);\n\n/* Create and send a onion response sent initially to dest with.\n * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret);\n\n/* Function to handle/send received decrypted versions of the packet sent with send_onion_packet.\n *\n * return 0 on success.\n * return 1 on failure.\n *\n * Used to handle these packets that are received in a non traditional way (by TCP for example).\n *\n * Source family must be set to something else than AF_INET6 or AF_INET so that the callback gets called\n * when the response is received.\n */\nint onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce);\n\n/* Set the callback to be called when the dest ip_port doesn't have AF_INET6 or AF_INET as the family.\n *\n * Format: function(void *object, IP_Port dest, uint8_t *data, uint16_t length)\n */\nvoid set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t),\n                                void *object);\n\nOnion *new_onion(DHT *dht);\n\nvoid kill_onion(Onion *onion);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/onion_announce.c",
    "content": "/*\n* onion_announce.c -- Implementation of the announce part of docs/Prevent_Tracking.txt\n*\n*  Copyright (C) 2013 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"onion_announce.h\"\n#include \"LAN_discovery.h\"\n#include \"util.h\"\n\n#define PING_ID_TIMEOUT 20\n\n#define ANNOUNCE_REQUEST_SIZE_RECV (ONION_ANNOUNCE_REQUEST_SIZE + ONION_RETURN_3)\n\n#define DATA_REQUEST_MIN_SIZE ONION_DATA_REQUEST_MIN_SIZE\n#define DATA_REQUEST_MIN_SIZE_RECV (DATA_REQUEST_MIN_SIZE + ONION_RETURN_3)\n\n/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE).\n *\n * dest_client_id is the public key of the node the packet will be sent to.\n * public_key and secret_key is the kepair which will be used to encrypt the request.\n * ping_id is the ping id that will be sent in the request.\n * client_id is the client id of the node we are searching for.\n * data_public_key is the public key we want others to encrypt their data packets with.\n * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to\n * receive back in the response.\n *\n * return -1 on failure.\n * return packet length on success.\n */\nint create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,\n                            const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id,\n                            const uint8_t *data_public_key, uint64_t sendback_data)\n{\n    if (max_packet_length < ONION_ANNOUNCE_REQUEST_SIZE)\n        return -1;\n\n    uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES +\n                  ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];\n    memcpy(plain, ping_id, ONION_PING_ID_SIZE);\n    memcpy(plain + ONION_PING_ID_SIZE, client_id, crypto_box_PUBLICKEYBYTES);\n    memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, data_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES, &sendback_data,\n           sizeof(sendback_data));\n\n    packet[0] = NET_PACKET_ANNOUNCE_REQUEST;\n    random_nonce(packet + 1);\n\n    int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, sizeof(plain),\n                           packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES);\n\n    if ((uint32_t)len + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES != ONION_ANNOUNCE_REQUEST_SIZE)\n        return -1;\n\n    memcpy(packet + 1 + crypto_box_NONCEBYTES, public_key, crypto_box_PUBLICKEYBYTES);\n\n    return ONION_ANNOUNCE_REQUEST_SIZE;\n}\n\n/* Create an onion data request packet in packet of max_packet_length (recommended size ONION_MAX_PACKET_SIZE).\n *\n * public_key is the real public key of the node which we want to send the data of length length to.\n * encrypt_public_key is the public key used to encrypt the data packet.\n *\n * nonce is the nonce to encrypt this packet with\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key,\n                        const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length)\n{\n    if (DATA_REQUEST_MIN_SIZE + length > max_packet_length)\n        return -1;\n\n    if ((unsigned int)DATA_REQUEST_MIN_SIZE + length > ONION_MAX_DATA_SIZE)\n        return -1;\n\n    packet[0] = NET_PACKET_ONION_DATA_REQUEST;\n    memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);\n\n    uint8_t random_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t random_secret_key[crypto_box_SECRETKEYBYTES];\n    crypto_box_keypair(random_public_key, random_secret_key);\n\n    memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, random_public_key, crypto_box_PUBLICKEYBYTES);\n\n    int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + crypto_box_PUBLICKEYBYTES, data, length,\n                           packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES);\n\n    if (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + len != DATA_REQUEST_MIN_SIZE +\n            length)\n        return -1;\n\n    return DATA_REQUEST_MIN_SIZE + length;\n}\n\n/* Create and send an onion announce request packet.\n *\n * path is the path the request will take before it is sent to dest.\n *\n * public_key and secret_key is the kepair which will be used to encrypt the request.\n * ping_id is the ping id that will be sent in the request.\n * client_id is the client id of the node we are searching for.\n * data_public_key is the public key we want others to encrypt their data packets with.\n * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to\n * receive back in the response.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_announce_request(Networking_Core *net, const Onion_Path *path, Node_format dest, const uint8_t *public_key,\n                          const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key,\n                          uint64_t sendback_data)\n{\n    uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE];\n    int len = create_announce_request(request, sizeof(request), dest.public_key, public_key, secret_key, ping_id, client_id,\n                                      data_public_key, sendback_data);\n\n    if (len != sizeof(request))\n        return -1;\n\n    uint8_t packet[ONION_MAX_PACKET_SIZE];\n    len = create_onion_packet(packet, sizeof(packet), path, dest.ip_port, request, sizeof(request));\n\n    if (len == -1)\n        return -1;\n\n    if (sendpacket(net, path->ip_port1, packet, len) != len)\n        return -1;\n\n    return 0;\n}\n\n/* Create and send an onion data request packet.\n *\n * path is the path the request will take before it is sent to dest.\n * (if dest knows the person with the public_key they should\n * send the packet to that person in the form of a response)\n *\n * public_key is the real public key of the node which we want to send the data of length length to.\n * encrypt_public_key is the public key used to encrypt the data packet.\n *\n * nonce is the nonce to encrypt this packet with\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key,\n                      const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length)\n{\n    uint8_t request[ONION_MAX_DATA_SIZE];\n    int len = create_data_request(request, sizeof(request), public_key, encrypt_public_key, nonce, data, length);\n\n    if (len == -1)\n        return -1;\n\n    uint8_t packet[ONION_MAX_PACKET_SIZE];\n    len = create_onion_packet(packet, sizeof(packet), path, dest, request, len);\n\n    if (len == -1)\n        return -1;\n\n    if (sendpacket(net, path->ip_port1, packet, len) != len)\n        return -1;\n\n    return 0;\n}\n\n/* Generate a ping_id and put it in ping_id */\nstatic void generate_ping_id(const Onion_Announce *onion_a, uint64_t time, const uint8_t *public_key,\n                             IP_Port ret_ip_port, uint8_t *ping_id)\n{\n    time /= PING_ID_TIMEOUT;\n    uint8_t data[crypto_box_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES + sizeof(ret_ip_port)];\n    memcpy(data, onion_a->secret_bytes, crypto_box_KEYBYTES);\n    memcpy(data + crypto_box_KEYBYTES, &time, sizeof(time));\n    memcpy(data + crypto_box_KEYBYTES + sizeof(time), public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(data + crypto_box_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES, &ret_ip_port, sizeof(ret_ip_port));\n    crypto_hash_sha256(ping_id, data, sizeof(data));\n}\n\n/* check if public key is in entries list\n *\n * return -1 if no\n * return position in list if yes\n */\nstatic int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key)\n{\n    unsigned int i;\n\n    for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) {\n        if (!is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT)\n                && public_key_cmp(onion_a->entries[i].public_key, public_key) == 0)\n            return i;\n    }\n\n    return -1;\n}\n\nstatic uint8_t cmp_public_key[crypto_box_PUBLICKEYBYTES];\nstatic int cmp_entry(const void *a, const void *b)\n{\n    Onion_Announce_Entry entry1, entry2;\n    memcpy(&entry1, a, sizeof(Onion_Announce_Entry));\n    memcpy(&entry2, b, sizeof(Onion_Announce_Entry));\n    int t1 = is_timeout(entry1.time, ONION_ANNOUNCE_TIMEOUT);\n    int t2 = is_timeout(entry2.time, ONION_ANNOUNCE_TIMEOUT);\n\n    if (t1 && t2)\n        return 0;\n\n    if (t1)\n        return -1;\n\n    if (t2)\n        return 1;\n\n    int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key);\n\n    if (close == 1)\n        return 1;\n\n    if (close == 2)\n        return -1;\n\n    return 0;\n}\n\n/* add entry to entries list\n *\n * return -1 if failure\n * return position if added\n */\nstatic int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, const uint8_t *public_key,\n                          const uint8_t *data_public_key, const uint8_t *ret)\n{\n\n    int pos = in_entries(onion_a, public_key);\n\n    unsigned int i;\n\n    if (pos == -1) {\n        for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) {\n            if (is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT))\n                pos = i;\n        }\n    }\n\n    if (pos == -1) {\n        if (id_closest(onion_a->dht->self_public_key, public_key, onion_a->entries[0].public_key) == 1)\n            pos = 0;\n    }\n\n    if (pos == -1)\n        return -1;\n\n    memcpy(onion_a->entries[pos].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    onion_a->entries[pos].ret_ip_port = ret_ip_port;\n    memcpy(onion_a->entries[pos].ret, ret, ONION_RETURN_3);\n    memcpy(onion_a->entries[pos].data_public_key, data_public_key, crypto_box_PUBLICKEYBYTES);\n    onion_a->entries[pos].time = unix_time();\n\n    memcpy(cmp_public_key, onion_a->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    qsort(onion_a->entries, ONION_ANNOUNCE_MAX_ENTRIES, sizeof(Onion_Announce_Entry), cmp_entry);\n    return in_entries(onion_a, public_key);\n}\n\nstatic int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion_Announce *onion_a = object;\n\n    if (length != ANNOUNCE_REQUEST_SIZE_RECV)\n        return 1;\n\n    const uint8_t *packet_public_key = packet + 1 + crypto_box_NONCEBYTES;\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n    get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key);\n\n    uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES +\n                  ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];\n    int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,\n                                     ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH +\n                                     crypto_box_MACBYTES, plain);\n\n    if ((uint32_t)len != sizeof(plain))\n        return 1;\n\n    uint8_t ping_id1[ONION_PING_ID_SIZE];\n    generate_ping_id(onion_a, unix_time(), packet_public_key, source, ping_id1);\n\n    uint8_t ping_id2[ONION_PING_ID_SIZE];\n    generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet_public_key, source, ping_id2);\n\n    int index = -1;\n\n    uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES;\n\n    if (sodium_memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0\n            || sodium_memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) {\n        index = add_to_entries(onion_a, source, packet_public_key, data_public_key,\n                               packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3));\n    } else {\n        index = in_entries(onion_a, plain + ONION_PING_ID_SIZE);\n    }\n\n    /*Respond with a announce response packet*/\n    Node_format nodes_list[MAX_SENT_NODES];\n    unsigned int num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0,\n                             LAN_ip(source.ip) == 0, 1);\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    random_nonce(nonce);\n\n    uint8_t pl[1 + ONION_PING_ID_SIZE + sizeof(nodes_list)];\n\n    if (index == -1) {\n        pl[0] = 0;\n        memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE);\n    } else {\n        if (public_key_cmp(onion_a->entries[index].public_key, packet_public_key) == 0) {\n            if (public_key_cmp(onion_a->entries[index].data_public_key, data_public_key) != 0) {\n                pl[0] = 0;\n                memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE);\n            } else {\n                pl[0] = 2;\n                memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE);\n            }\n        } else {\n            pl[0] = 1;\n            memcpy(pl + 1, onion_a->entries[index].data_public_key, crypto_box_PUBLICKEYBYTES);\n        }\n    }\n\n    int nodes_length = 0;\n\n    if (num_nodes != 0) {\n        nodes_length = pack_nodes(pl + 1 + ONION_PING_ID_SIZE, sizeof(nodes_list), nodes_list, num_nodes);\n\n        if (nodes_length <= 0)\n            return 1;\n    }\n\n    uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE];\n    len = encrypt_data_symmetric(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + nodes_length,\n                                 data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES);\n\n    if (len != 1 + ONION_PING_ID_SIZE + nodes_length + crypto_box_MACBYTES)\n        return 1;\n\n    data[0] = NET_PACKET_ANNOUNCE_RESPONSE;\n    memcpy(data + 1, plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES,\n           ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);\n    memcpy(data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, nonce, crypto_box_NONCEBYTES);\n\n    if (send_onion_response(onion_a->net, source, data,\n                            1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES + len,\n                            packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)) == -1)\n        return 1;\n\n    return 0;\n}\n\nstatic int handle_data_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion_Announce *onion_a = object;\n\n    if (length <= DATA_REQUEST_MIN_SIZE_RECV)\n        return 1;\n\n    if (length > ONION_MAX_PACKET_SIZE)\n        return 1;\n\n    int index = in_entries(onion_a, packet + 1);\n\n    if (index == -1)\n        return 1;\n\n    uint8_t data[length - (crypto_box_PUBLICKEYBYTES + ONION_RETURN_3)];\n    data[0] = NET_PACKET_ONION_DATA_RESPONSE;\n    memcpy(data + 1, packet + 1 + crypto_box_PUBLICKEYBYTES, length - (1 + crypto_box_PUBLICKEYBYTES + ONION_RETURN_3));\n\n    if (send_onion_response(onion_a->net, onion_a->entries[index].ret_ip_port, data, sizeof(data),\n                            onion_a->entries[index].ret) == -1)\n        return 1;\n\n    return 0;\n}\n\nOnion_Announce *new_onion_announce(DHT *dht)\n{\n    if (dht == NULL)\n        return NULL;\n\n    Onion_Announce *onion_a = calloc(1, sizeof(Onion_Announce));\n\n    if (onion_a == NULL)\n        return NULL;\n\n    onion_a->dht = dht;\n    onion_a->net = dht->net;\n    new_symmetric_key(onion_a->secret_bytes);\n\n    networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a);\n    networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, &handle_data_request, onion_a);\n\n    return onion_a;\n}\n\nvoid kill_onion_announce(Onion_Announce *onion_a)\n{\n    if (onion_a == NULL)\n        return;\n\n    networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, NULL, NULL);\n    networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, NULL, NULL);\n    free(onion_a);\n}\n"
  },
  {
    "path": "toxcore/onion_announce.h",
    "content": "/*\n* onion_announce.h -- Implementation of the announce part of docs/Prevent_Tracking.txt\n*\n*  Copyright (C) 2013 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n#ifndef ONION_ANNOUNCE_H\n#define ONION_ANNOUNCE_H\n\n#include \"onion.h\"\n\n#define ONION_ANNOUNCE_MAX_ENTRIES 160\n#define ONION_ANNOUNCE_TIMEOUT 300\n#define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES\n\n#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t))\n\n#define ONION_ANNOUNCE_REQUEST_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_MACBYTES)\n\n#define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES + 1 + ONION_PING_ID_SIZE + crypto_box_MACBYTES)\n#define ONION_ANNOUNCE_RESPONSE_MAX_SIZE (ONION_ANNOUNCE_RESPONSE_MIN_SIZE + sizeof(Node_format)*MAX_SENT_NODES)\n\n#define ONION_DATA_RESPONSE_MIN_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)\n\n#if ONION_PING_ID_SIZE != crypto_box_PUBLICKEYBYTES\n#error announce response packets assume that ONION_PING_ID_SIZE is equal to crypto_box_PUBLICKEYBYTES\n#endif\n\n#define ONION_DATA_REQUEST_MIN_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)\n#define MAX_DATA_REQUEST_SIZE (ONION_MAX_DATA_SIZE - ONION_DATA_REQUEST_MIN_SIZE)\n\ntypedef struct {\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    IP_Port ret_ip_port;\n    uint8_t ret[ONION_RETURN_3];\n    uint8_t data_public_key[crypto_box_PUBLICKEYBYTES];\n    uint64_t time;\n} Onion_Announce_Entry;\n\ntypedef struct {\n    DHT     *dht;\n    Networking_Core *net;\n    Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES];\n    /* This is crypto_box_KEYBYTES long just so we can use new_symmetric_key() to fill it */\n    uint8_t secret_bytes[crypto_box_KEYBYTES];\n\n    Shared_Keys shared_keys_recv;\n} Onion_Announce;\n\n/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE).\n *\n * dest_client_id is the public key of the node the packet will be sent to.\n * public_key and secret_key is the kepair which will be used to encrypt the request.\n * ping_id is the ping id that will be sent in the request.\n * client_id is the client id of the node we are searching for.\n * data_public_key is the public key we want others to encrypt their data packets with.\n * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to\n * receive back in the response.\n *\n * return -1 on failure.\n * return packet length on success.\n */\nint create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id,\n                            const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id,\n                            const uint8_t *data_public_key, uint64_t sendback_data);\n\n/* Create an onion data request packet in packet of max_packet_length (recommended size ONION_MAX_PACKET_SIZE).\n *\n * public_key is the real public key of the node which we want to send the data of length length to.\n * encrypt_public_key is the public key used to encrypt the data packet.\n *\n * nonce is the nonce to encrypt this packet with\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key,\n                        const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length);\n\n/* Create and send an onion announce request packet.\n *\n * path is the path the request will take before it is sent to dest.\n *\n * public_key and secret_key is the kepair which will be used to encrypt the request.\n * ping_id is the ping id that will be sent in the request.\n * client_id is the client id of the node we are searching for.\n * data_public_key is the public key we want others to encrypt their data packets with.\n * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to\n * receive back in the response.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_announce_request(Networking_Core *net, const Onion_Path *path, Node_format dest, const uint8_t *public_key,\n                          const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key,\n                          uint64_t sendback_data);\n\n/* Create and send an onion data request packet.\n *\n * path is the path the request will take before it is sent to dest.\n * (if dest knows the person with the public_key they should\n * send the packet to that person in the form of a response)\n *\n * public_key is the real public key of the node which we want to send the data of length length to.\n * encrypt_public_key is the public key used to encrypt the data packet.\n *\n * nonce is the nonce to encrypt this packet with\n *\n * The maximum length of data is MAX_DATA_REQUEST_SIZE.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key,\n                      const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length);\n\n\nOnion_Announce *new_onion_announce(DHT *dht);\n\nvoid kill_onion_announce(Onion_Announce *onion_a);\n\n\n#endif\n"
  },
  {
    "path": "toxcore/onion_client.c",
    "content": "/*\n* onion_client.c -- Implementation of the client part of docs/Prevent_Tracking.txt\n*                   (The part that uses the onion stuff to connect to the friend)\n*\n*  Copyright (C) 2013 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"onion_client.h\"\n#include \"util.h\"\n#include \"LAN_discovery.h\"\n\n/* defines for the array size and\n   timeout for onion announce packets. */\n#define ANNOUNCE_ARRAY_SIZE 256\n#define ANNOUNCE_TIMEOUT 10\n\n/* Add a node to the path_nodes bootstrap array.\n *\n * return -1 on failure\n * return 0 on success\n */\nint onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key)\n{\n    if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6)\n        return -1;\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_PATH_NODES; ++i) {\n        if (public_key_cmp(public_key, onion_c->path_nodes_bs[i].public_key) == 0)\n            return -1;\n    }\n\n    onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].ip_port = ip_port;\n    memcpy(onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].public_key, public_key,\n           crypto_box_PUBLICKEYBYTES);\n\n    uint16_t last = onion_c->path_nodes_index_bs;\n    ++onion_c->path_nodes_index_bs;\n\n    if (onion_c->path_nodes_index_bs < last)\n        onion_c->path_nodes_index_bs = MAX_PATH_NODES + 1;\n\n    return 0;\n}\n\n/* Add a node to the path_nodes array.\n *\n * return -1 on failure\n * return 0 on success\n */\nstatic int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key)\n{\n    if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6)\n        return -1;\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_PATH_NODES; ++i) {\n        if (public_key_cmp(public_key, onion_c->path_nodes[i].public_key) == 0)\n            return -1;\n    }\n\n    onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].ip_port = ip_port;\n    memcpy(onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].public_key, public_key,\n           crypto_box_PUBLICKEYBYTES);\n\n    uint16_t last = onion_c->path_nodes_index;\n    ++onion_c->path_nodes_index;\n\n    if (onion_c->path_nodes_index < last)\n        onion_c->path_nodes_index = MAX_PATH_NODES + 1;\n\n    return 0;\n}\n\n/* Put up to max_num nodes in nodes.\n *\n * return the number of nodes.\n */\nuint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num)\n{\n    unsigned int i;\n\n    if (!max_num)\n        return 0;\n\n    unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;\n\n    if (num_nodes == 0)\n        return 0;\n\n    if (num_nodes < max_num)\n        max_num = num_nodes;\n\n    for (i = 0; i < max_num; ++i) {\n        nodes[i] = onion_c->path_nodes[(onion_c->path_nodes_index - (1 + i)) % num_nodes];\n    }\n\n    return max_num;\n}\n\n/* Put up to max_num random nodes in nodes.\n *\n * return the number of nodes.\n */\nstatic uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num)\n{\n    unsigned int i;\n\n    if (!max_num)\n        return 0;\n\n    unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;\n\n    //if (DHT_non_lan_connected(onion_c->dht)) {\n    if (DHT_isconnected(onion_c->dht)) {\n        if (num_nodes == 0)\n            return 0;\n\n        for (i = 0; i < max_num; ++i) {\n            nodes[i] = onion_c->path_nodes[rand() % num_nodes];\n        }\n    } else {\n        int random_tcp = get_random_tcp_con_number(onion_c->c);\n\n        if (random_tcp == -1) {\n            return 0;\n        }\n\n        if (num_nodes >= 2) {\n            nodes[0].ip_port.ip.family = TCP_FAMILY;\n            nodes[0].ip_port.ip.ip4.uint32 = random_tcp;\n\n            for (i = 1; i < max_num; ++i) {\n                nodes[i] = onion_c->path_nodes[rand() % num_nodes];\n            }\n        } else {\n            unsigned int num_nodes_bs = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs :\n                                        MAX_PATH_NODES;\n\n            if (num_nodes_bs == 0)\n                return 0;\n\n            nodes[0].ip_port.ip.family = TCP_FAMILY;\n            nodes[0].ip_port.ip.ip4.uint32 = random_tcp;\n\n            for (i = 1; i < max_num; ++i) {\n                nodes[i] = onion_c->path_nodes_bs[rand() % num_nodes_bs];\n            }\n        }\n    }\n\n    return max_num;\n}\n\n/*\n * return -1 if nodes are suitable for creating a new path.\n * return path number of already existing similar path if one already exists.\n */\nstatic int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format *nodes)\n{\n    unsigned int i;\n\n    for (i = 0; i < NUMBER_ONION_PATHS; ++i) {\n        if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) {\n            continue;\n        }\n\n        if (is_timeout(onion_paths->path_creation_time[i], ONION_PATH_MAX_LIFETIME)) {\n            continue;\n        }\n\n        // TODO: do we really have to check it with the last node?\n        if (ipport_equal(&onion_paths->paths[i].ip_port1, &nodes[ONION_PATH_LENGTH - 1].ip_port)) {\n            return i;\n        }\n    }\n\n    return -1;\n}\n\n/* is path timed out */\nstatic _Bool path_timed_out(Onion_Client_Paths *onion_paths, uint32_t pathnum)\n{\n    pathnum = pathnum % NUMBER_ONION_PATHS;\n\n    return ((onion_paths->last_path_success[pathnum] + ONION_PATH_TIMEOUT < onion_paths->last_path_used[pathnum]\n             && onion_paths->last_path_used_times[pathnum] >= ONION_PATH_MAX_NO_RESPONSE_USES)\n            || is_timeout(onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME));\n}\n\n/* Create a new path or use an old suitable one (if pathnum is valid)\n * or a random one from onion_paths.\n *\n * return -1 on failure\n * return 0 on success\n *\n * TODO: Make this function better, it currently probably is vulnerable to some attacks that\n * could de anonimize us.\n */\nstatic int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_paths, uint32_t pathnum, Onion_Path *path)\n{\n    if (pathnum == UINT32_MAX) {\n        pathnum = rand() % NUMBER_ONION_PATHS;\n    } else {\n        pathnum = pathnum % NUMBER_ONION_PATHS;\n    }\n\n    if (path_timed_out(onion_paths, pathnum)) {\n        Node_format nodes[ONION_PATH_LENGTH];\n\n        if (random_nodes_path_onion(onion_c, nodes, ONION_PATH_LENGTH) != ONION_PATH_LENGTH)\n            return -1;\n\n        int n = is_path_used(onion_paths, nodes);\n\n        if (n == -1) {\n            if (create_onion_path(onion_c->dht, &onion_paths->paths[pathnum], nodes) == -1)\n                return -1;\n\n            onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT;\n            onion_paths->path_creation_time[pathnum] = unix_time();\n            onion_paths->last_path_used_times[pathnum] = ONION_PATH_MAX_NO_RESPONSE_USES / 2;\n\n            uint32_t path_num = rand();\n            path_num /= NUMBER_ONION_PATHS;\n            path_num *= NUMBER_ONION_PATHS;\n            path_num += pathnum;\n\n            onion_paths->paths[pathnum].path_num = path_num;\n        } else {\n            pathnum = n;\n        }\n    }\n\n    ++onion_paths->last_path_used_times[pathnum];\n    onion_paths->last_path_used[pathnum] = unix_time();\n    memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path));\n    return 0;\n}\n\n/* Does path with path_num exist. */\nstatic _Bool path_exists(Onion_Client_Paths *onion_paths, uint32_t path_num)\n{\n    if (path_timed_out(onion_paths, path_num))\n        return 0;\n\n    return onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num;\n}\n\n/* Set path timeouts, return the path number.\n *\n */\nstatic uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, uint32_t path_num)\n{\n    if (num > onion_c->num_friends)\n        return -1;\n\n    Onion_Client_Paths *onion_paths;\n\n    if (num == 0) {\n        onion_paths = &onion_c->onion_paths_self;\n    } else {\n        onion_paths = &onion_c->onion_paths_friends;\n    }\n\n    if (onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num) {\n        onion_paths->last_path_success[path_num % NUMBER_ONION_PATHS] = unix_time();\n        onion_paths->last_path_used_times[path_num % NUMBER_ONION_PATHS] = 0;\n\n        Node_format nodes[ONION_PATH_LENGTH];\n\n        if (onion_path_to_nodes(nodes, ONION_PATH_LENGTH, &onion_paths->paths[path_num % NUMBER_ONION_PATHS]) == 0) {\n            unsigned int i;\n\n            for (i = 0; i < ONION_PATH_LENGTH; ++i) {\n                onion_add_path_node(onion_c, nodes[i].ip_port, nodes[i].public_key);\n            }\n        }\n\n        return path_num;\n    }\n\n    return ~0;\n}\n\n/* Function to send onion packet via TCP and UDP.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nstatic int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, IP_Port dest,\n                                     const uint8_t *data, uint16_t length)\n{\n    if (path->ip_port1.ip.family == AF_INET || path->ip_port1.ip.family == AF_INET6) {\n        uint8_t packet[ONION_MAX_PACKET_SIZE];\n        int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length);\n\n        if (len == -1)\n            return -1;\n\n        if (sendpacket(onion_c->net, path->ip_port1, packet, len) != len)\n            return -1;\n\n        return 0;\n    } else if (path->ip_port1.ip.family == TCP_FAMILY) {\n        uint8_t packet[ONION_MAX_PACKET_SIZE];\n        int len = create_onion_packet_tcp(packet, sizeof(packet), path, dest, data, length);\n\n        if (len == -1)\n            return -1;\n\n        return send_tcp_onion_request(onion_c->c, path->ip_port1.ip.ip4.uint32, packet, len);\n    } else {\n        return -1;\n    }\n}\n\n/* Creates a sendback for use in an announce request.\n *\n * num is 0 if we used our secret public key for the announce\n * num is 1 + friendnum if we use a temporary one.\n *\n * Public key is the key we will be sending it to.\n * ip_port is the ip_port of the node we will be sending\n * it to.\n *\n * sendback must be at least ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big\n *\n * return -1 on failure\n * return 0 on success\n *\n */\nstatic int new_sendback(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, IP_Port ip_port,\n                        uint32_t path_num, uint64_t *sendback)\n{\n    uint8_t data[sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + sizeof(uint32_t)];\n    memcpy(data, &num, sizeof(uint32_t));\n    memcpy(data + sizeof(uint32_t), public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES, &ip_port, sizeof(IP_Port));\n    memcpy(data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port), &path_num, sizeof(uint32_t));\n    *sendback = ping_array_add(&onion_c->announce_ping_array, data, sizeof(data));\n\n    if (*sendback == 0)\n        return -1;\n\n    return 0;\n}\n\n/* Checks if the sendback is valid and returns the public key contained in it in ret_pubkey and the\n * ip contained in it in ret_ip_port\n *\n * sendback is the sendback ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big\n * ret_pubkey must be at least crypto_box_PUBLICKEYBYTES big\n * ret_ip_port must be at least 1 big\n *\n * return ~0 on failure\n * return num (see new_sendback(...)) on success\n */\nstatic uint32_t check_sendback(Onion_Client *onion_c, const uint8_t *sendback, uint8_t *ret_pubkey,\n                               IP_Port *ret_ip_port, uint32_t *path_num)\n{\n    uint64_t sback;\n    memcpy(&sback, sendback, sizeof(uint64_t));\n    uint8_t data[sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + sizeof(uint32_t)];\n\n    if (ping_array_check(data, sizeof(data), &onion_c->announce_ping_array, sback) != sizeof(data))\n        return ~0;\n\n    memcpy(ret_pubkey, data + sizeof(uint32_t), crypto_box_PUBLICKEYBYTES);\n    memcpy(ret_ip_port, data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port));\n    memcpy(path_num, data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port), sizeof(uint32_t));\n\n    uint32_t num;\n    memcpy(&num, data, sizeof(uint32_t));\n    return num;\n}\n\nstatic int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_Port dest, const uint8_t *dest_pubkey,\n                                        const uint8_t *ping_id, uint32_t pathnum)\n{\n    if (num > onion_c->num_friends)\n        return -1;\n\n    uint64_t sendback;\n    Onion_Path path;\n\n    if (num == 0) {\n        if (random_path(onion_c, &onion_c->onion_paths_self, pathnum, &path) == -1)\n            return -1;\n    } else {\n        if (random_path(onion_c, &onion_c->onion_paths_friends, pathnum, &path) == -1)\n            return -1;\n    }\n\n    if (new_sendback(onion_c, num, dest_pubkey, dest, path.path_num, &sendback) == -1)\n        return -1;\n\n    uint8_t zero_ping_id[ONION_PING_ID_SIZE] = {0};\n\n    if (ping_id == NULL)\n        ping_id = zero_ping_id;\n\n    uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE];\n    int len;\n\n    if (num == 0) {\n        len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->c->self_public_key,\n                                      onion_c->c->self_secret_key, ping_id, onion_c->c->self_public_key, onion_c->temp_public_key, sendback);\n\n    } else {\n        len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->friends_list[num - 1].temp_public_key,\n                                      onion_c->friends_list[num - 1].temp_secret_key, ping_id, onion_c->friends_list[num - 1].real_public_key, zero_ping_id,\n                                      sendback);\n    }\n\n    if (len == -1) {\n        return -1;\n    }\n\n    return send_onion_packet_tcp_udp(onion_c, &path, dest, request, len);\n}\n\nstatic uint8_t cmp_public_key[crypto_box_PUBLICKEYBYTES];\nstatic int cmp_entry(const void *a, const void *b)\n{\n    Onion_Node entry1, entry2;\n    memcpy(&entry1, a, sizeof(Onion_Node));\n    memcpy(&entry2, b, sizeof(Onion_Node));\n    int t1 = is_timeout(entry1.timestamp, ONION_NODE_TIMEOUT);\n    int t2 = is_timeout(entry2.timestamp, ONION_NODE_TIMEOUT);\n\n    if (t1 && t2)\n        return 0;\n\n    if (t1)\n        return -1;\n\n    if (t2)\n        return 1;\n\n    int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key);\n\n    if (close == 1)\n        return 1;\n\n    if (close == 2)\n        return -1;\n\n    return 0;\n}\n\nstatic int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, IP_Port ip_port,\n                              uint8_t is_stored, const uint8_t *pingid_or_key, uint32_t path_num)\n{\n    if (num > onion_c->num_friends)\n        return -1;\n\n    Onion_Node *list_nodes = NULL;\n    uint8_t *reference_id = NULL;\n    unsigned int list_length;\n\n    if (num == 0) {\n        list_nodes = onion_c->clients_announce_list;\n        reference_id = onion_c->c->self_public_key;\n        list_length = MAX_ONION_CLIENTS_ANNOUNCE;\n\n        if (is_stored == 1 && public_key_cmp(pingid_or_key, onion_c->temp_public_key) != 0) {\n            is_stored = 0;\n        }\n\n    } else {\n        if (is_stored >= 2)\n            return -1;\n\n        list_nodes = onion_c->friends_list[num - 1].clients_list;\n        reference_id = onion_c->friends_list[num - 1].real_public_key;\n        list_length = MAX_ONION_CLIENTS;\n    }\n\n    memcpy(cmp_public_key, reference_id, crypto_box_PUBLICKEYBYTES);\n    qsort(list_nodes, list_length, sizeof(Onion_Node), cmp_entry);\n\n    int index = -1, stored = 0;\n    unsigned int i;\n\n    if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT)\n            || id_closest(reference_id, list_nodes[0].public_key, public_key) == 2) {\n        index = 0;\n    }\n\n    for (i = 0; i < list_length; ++i) {\n        if (public_key_cmp(list_nodes[i].public_key, public_key) == 0) {\n            index = i;\n            stored = 1;\n            break;\n        }\n    }\n\n    if (index == -1)\n        return 0;\n\n    memcpy(list_nodes[index].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    list_nodes[index].ip_port = ip_port;\n\n    //TODO: remove this and find a better source of nodes to use for paths.\n    onion_add_path_node(onion_c, ip_port, public_key);\n\n    if (is_stored == 1) {\n        memcpy(list_nodes[index].data_public_key, pingid_or_key, crypto_box_PUBLICKEYBYTES);\n    } else {\n        memcpy(list_nodes[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE);\n    }\n\n    list_nodes[index].is_stored = is_stored;\n    list_nodes[index].timestamp = unix_time();\n\n    if (!stored)\n        list_nodes[index].last_pinged = 0;\n\n    list_nodes[index].path_used = set_path_timeouts(onion_c, num, path_num);\n    return 0;\n}\n\nstatic int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, const uint8_t *public_key)\n{\n    unsigned int i;\n\n    for (i = 0; i < MAX_STORED_PINGED_NODES; ++i) {\n        if (!is_timeout(last_pinged[i].timestamp, MIN_NODE_PING_TIME))\n            if (public_key_cmp(last_pinged[i].public_key, public_key) == 0)\n                return 0;\n    }\n\n    memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = unix_time();\n    ++*last_pinged_index;\n    return 1;\n}\n\nstatic int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_format *nodes, uint16_t num_nodes,\n                             IP_Port source)\n{\n    if (num > onion_c->num_friends)\n        return -1;\n\n    if (num_nodes == 0)\n        return 0;\n\n    Onion_Node *list_nodes = NULL;\n    uint8_t *reference_id = NULL;\n    unsigned int list_length;\n\n    Last_Pinged *last_pinged = NULL;\n    uint8_t *last_pinged_index = NULL;\n\n    if (num == 0) {\n        list_nodes = onion_c->clients_announce_list;\n        reference_id = onion_c->c->self_public_key;\n        list_length = MAX_ONION_CLIENTS_ANNOUNCE;\n        last_pinged = onion_c->last_pinged;\n        last_pinged_index = &onion_c->last_pinged_index;\n    } else {\n        list_nodes = onion_c->friends_list[num - 1].clients_list;\n        reference_id = onion_c->friends_list[num - 1].real_public_key;\n        list_length = MAX_ONION_CLIENTS;\n        last_pinged = onion_c->friends_list[num - 1].last_pinged;\n        last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index;\n    }\n\n    unsigned int i, j;\n    int lan_ips_accepted = (LAN_ip(source.ip) == 0);\n\n    for (i = 0; i < num_nodes; ++i) {\n\n        if (!lan_ips_accepted)\n            if (LAN_ip(nodes[i].ip_port.ip) == 0)\n                continue;\n\n        if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT)\n                || id_closest(reference_id, list_nodes[0].public_key, nodes[i].public_key) == 2\n                || is_timeout(list_nodes[1].timestamp, ONION_NODE_TIMEOUT)\n                || id_closest(reference_id, list_nodes[1].public_key, nodes[i].public_key) == 2 ) {\n            /* check if node is already in list. */\n            for (j = 0; j < list_length; ++j) {\n                if (public_key_cmp(list_nodes[j].public_key, nodes[i].public_key) == 0) {\n                    break;\n                }\n            }\n\n            if (j == list_length && good_to_ping(last_pinged, last_pinged_index, nodes[i].public_key)) {\n                client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].public_key, NULL, ~0);\n            }\n        }\n    }\n\n    return 0;\n}\n\nstatic int handle_announce_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion_Client *onion_c = object;\n\n    if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE)\n        return 1;\n\n    uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE;\n\n    uint8_t public_key[crypto_box_PUBLICKEYBYTES];\n    IP_Port ip_port;\n    uint32_t path_num;\n    uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num);\n\n    if (num > onion_c->num_friends)\n        return 1;\n\n    uint8_t plain[1 + ONION_PING_ID_SIZE + len_nodes];\n    int len = -1;\n\n    if (num == 0) {\n        len = decrypt_data(public_key, onion_c->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,\n                           packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES,\n                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES), plain);\n    } else {\n        if (onion_c->friends_list[num - 1].status == 0)\n            return 1;\n\n        len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key,\n                           packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,\n                           packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES,\n                           length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES), plain);\n    }\n\n    if ((uint32_t)len != sizeof(plain))\n        return 1;\n\n    if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1, path_num) == -1)\n        return 1;\n\n    if (len_nodes != 0) {\n        Node_format nodes[MAX_SENT_NODES];\n        int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, plain + 1 + ONION_PING_ID_SIZE, len_nodes, 0);\n\n        if (num_nodes <= 0)\n            return 1;\n\n        if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1)\n            return 1;\n    }\n\n    //TODO: LAN vs non LAN ips?, if we are connected only to LAN, are we offline?\n    onion_c->last_packet_recv = unix_time();\n    return 0;\n}\n\n#define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE\n\nstatic int handle_data_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    Onion_Client *onion_c = object;\n\n    if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE))\n        return 1;\n\n    if (length > MAX_DATA_REQUEST_SIZE)\n        return 1;\n\n    uint8_t temp_plain[length - ONION_DATA_RESPONSE_MIN_SIZE];\n    int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion_c->temp_secret_key, packet + 1,\n                           packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,\n                           length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), temp_plain);\n\n    if ((uint32_t)len != sizeof(temp_plain))\n        return 1;\n\n    uint8_t plain[sizeof(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE];\n    len = decrypt_data(temp_plain, onion_c->c->self_secret_key, packet + 1, temp_plain + crypto_box_PUBLICKEYBYTES,\n                       sizeof(temp_plain) - crypto_box_PUBLICKEYBYTES, plain);\n\n    if ((uint32_t)len != sizeof(plain))\n        return 1;\n\n    if (!onion_c->Onion_Data_Handlers[plain[0]].function)\n        return 1;\n\n    return onion_c->Onion_Data_Handlers[plain[0]].function(onion_c->Onion_Data_Handlers[plain[0]].object, temp_plain, plain,\n            sizeof(plain));\n}\n\n#define DHTPK_DATA_MIN_LENGTH (1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES)\n#define DHTPK_DATA_MAX_LENGTH (DHTPK_DATA_MIN_LENGTH + sizeof(Node_format)*MAX_SENT_NODES)\nstatic int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length)\n{\n    Onion_Client *onion_c = object;\n\n    if (length < DHTPK_DATA_MIN_LENGTH)\n        return 1;\n\n    if (length > DHTPK_DATA_MAX_LENGTH)\n        return 1;\n\n    int friend_num = onion_friend_num(onion_c, source_pubkey);\n\n    if (friend_num == -1)\n        return 1;\n\n    uint64_t no_replay;\n    memcpy(&no_replay, data + 1, sizeof(uint64_t));\n    net_to_host((uint8_t *) &no_replay, sizeof(no_replay));\n\n    if (no_replay <= onion_c->friends_list[friend_num].last_noreplay)\n        return 1;\n\n    onion_c->friends_list[friend_num].last_noreplay = no_replay;\n\n    if (onion_c->friends_list[friend_num].dht_pk_callback)\n        onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object,\n                onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t));\n\n    onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t));\n    onion_c->friends_list[friend_num].last_seen = unix_time();\n\n    uint16_t len_nodes = length - DHTPK_DATA_MIN_LENGTH;\n\n    if (len_nodes != 0) {\n        Node_format nodes[MAX_SENT_NODES];\n        int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES,\n                                     len_nodes, 1);\n\n        if (num_nodes <= 0)\n            return 1;\n\n        int i;\n\n        for (i = 0; i < num_nodes; ++i) {\n            uint8_t family = nodes[i].ip_port.ip.family;\n\n            if (family == AF_INET || family == AF_INET6) {\n                DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key);\n            } else if (family == TCP_INET || family == TCP_INET6) {\n                if (onion_c->friends_list[friend_num].tcp_relay_node_callback) {\n                    void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object;\n                    uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number;\n                    onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].public_key);\n                }\n            }\n        }\n    }\n\n    return 0;\n}\n\nstatic int handle_tcp_onion(void *object, const uint8_t *data, uint16_t length)\n{\n    if (length == 0)\n        return 1;\n\n    IP_Port ip_port = {0};\n    ip_port.ip.family = TCP_FAMILY;\n\n    if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE) {\n        return handle_announce_response(object, ip_port, data, length);\n    } else if (data[0] == NET_PACKET_ONION_DATA_RESPONSE) {\n        return handle_data_response(object, ip_port, data, length);\n    }\n\n    return 1;\n}\n\n/* Send data of length length to friendnum.\n * This data will be received by the friend using the Onion_Data_Handlers callbacks.\n *\n * Even if this function succeeds, the friend might not receive any data.\n *\n * return the number of packets sent on success\n * return -1 on failure.\n */\nint send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE)\n        return -1;\n\n    if (length == 0)\n        return -1;\n\n    unsigned int i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0;\n    Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list;\n\n    for (i = 0; i < MAX_ONION_CLIENTS; ++i) {\n        if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT))\n            continue;\n\n        ++num_nodes;\n\n        if (list_nodes[i].is_stored) {\n            good_nodes[num_good] = i;\n            ++num_good;\n        }\n    }\n\n    if (num_good < (num_nodes / 4) + 1)\n        return -1;\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    random_nonce(nonce);\n\n    uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length];\n    memcpy(packet, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES);\n    int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data,\n                           length, packet + crypto_box_PUBLICKEYBYTES);\n\n    if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet))\n        return -1;\n\n    unsigned int good = 0;\n\n    for (i = 0; i < num_good; ++i) {\n        Onion_Path path;\n\n        if (random_path(onion_c, &onion_c->onion_paths_friends, ~0, &path) == -1)\n            continue;\n\n        uint8_t o_packet[ONION_MAX_PACKET_SIZE];\n        len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key,\n                                  list_nodes[good_nodes[i]].data_public_key, nonce, packet, sizeof(packet));\n\n        if (len == -1)\n            continue;\n\n        if (send_onion_packet_tcp_udp(onion_c, &path, list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0)\n            ++good;\n    }\n\n    return good;\n}\n\n/* Try to send the dht public key via the DHT instead of onion\n *\n * Even if this function succeeds, the friend might not receive any data.\n *\n * return the number of packets sent on success\n * return -1 on failure.\n */\nstatic int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    if (!onion_c->friends_list[friend_num].know_dht_public_key)\n        return -1;\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    new_nonce(nonce);\n\n    uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length];\n    memcpy(temp, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES);\n    memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);\n    int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data,\n                           length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);\n\n    if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp))\n        return -1;\n\n    uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];\n    len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet,\n                         onion_c->friends_list[friend_num].dht_public_key, temp, sizeof(temp), CRYPTO_PACKET_DHTPK);\n\n    if (len == -1)\n        return -1;\n\n    return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, packet, len);\n}\n\nstatic int handle_dht_dhtpk(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet,\n                            uint16_t length)\n{\n    Onion_Client *onion_c = object;\n\n    if (length < DHTPK_DATA_MIN_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES)\n        return 1;\n\n    if (length > DHTPK_DATA_MAX_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES)\n        return 1;\n\n    uint8_t plain[DHTPK_DATA_MAX_LENGTH];\n    int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES,\n                           packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,\n                           length - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES), plain);\n\n    if (len != length - (DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES))\n        return 1;\n\n    if (public_key_cmp(source_pubkey, plain + 1 + sizeof(uint64_t)) != 0)\n        return 1;\n\n    return handle_dhtpk_announce(onion_c, packet, plain, len);\n}\n/* Send the packets to tell our friends what our DHT public key is.\n *\n * if onion_dht_both is 0, use only the onion to send the packet.\n * if it is 1, use only the dht.\n * if it is something else, use both.\n *\n * return the number of packets sent on success\n * return -1 on failure.\n */\nstatic int send_dhtpk_announce(Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both)\n{\n    if (friend_num >= onion_c->num_friends)\n        return -1;\n\n    uint8_t data[DHTPK_DATA_MAX_LENGTH];\n    data[0] = ONION_DATA_DHTPK;\n    uint64_t no_replay = unix_time();\n    host_to_net((uint8_t *)&no_replay, sizeof(no_replay));\n    memcpy(data + 1, &no_replay, sizeof(no_replay));\n    memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    Node_format nodes[MAX_SENT_NODES];\n    uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, (MAX_SENT_NODES / 2));\n    uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays);\n    num_nodes += num_relays;\n    int nodes_len = 0;\n\n    if (num_nodes != 0) {\n        nodes_len = pack_nodes(data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH, nodes,\n                               num_nodes);\n\n        if (nodes_len <= 0)\n            return -1;\n    }\n\n    int num1 = -1, num2 = -1;\n\n    if (onion_dht_both != 1)\n        num1 = send_onion_data(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len);\n\n    if (onion_dht_both != 0)\n        num2 = send_dht_dhtpk(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len);\n\n    if (num1 == -1)\n        return num2;\n\n    if (num2 == -1)\n        return num1;\n\n    return num1 + num2;\n}\n\n/* Get the friend_num of a friend.\n *\n * return -1 on failure.\n * return friend number on success.\n */\nint onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key)\n{\n    unsigned int i;\n\n    for (i = 0; i < onion_c->num_friends; ++i) {\n        if (onion_c->friends_list[i].status == 0)\n            continue;\n\n        if (public_key_cmp(public_key, onion_c->friends_list[i].real_public_key) == 0)\n            return i;\n    }\n\n    return -1;\n}\n\n/* Set the size of the friend list to num.\n *\n *  return -1 if realloc fails.\n *  return 0 if it succeeds.\n */\nstatic int realloc_onion_friends(Onion_Client *onion_c, uint32_t num)\n{\n    if (num == 0) {\n        free(onion_c->friends_list);\n        onion_c->friends_list = NULL;\n        return 0;\n    }\n\n    Onion_Friend *newonion_friends = realloc(onion_c->friends_list, num * sizeof(Onion_Friend));\n\n    if (newonion_friends == NULL)\n        return -1;\n\n    onion_c->friends_list = newonion_friends;\n    return 0;\n}\n\n/* Add a friend who we want to connect to.\n *\n * return -1 on failure.\n * return the friend number on success or if the friend was already added.\n */\nint onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key)\n{\n    int num = onion_friend_num(onion_c, public_key);\n\n    if (num != -1)\n        return num;\n\n    unsigned int i, index = ~0;\n\n    for (i = 0; i < onion_c->num_friends; ++i) {\n        if (onion_c->friends_list[i].status == 0) {\n            index = i;\n            break;\n        }\n    }\n\n    if (index == (uint32_t)~0) {\n        if (realloc_onion_friends(onion_c, onion_c->num_friends + 1) == -1)\n            return -1;\n\n        index = onion_c->num_friends;\n        memset(&(onion_c->friends_list[onion_c->num_friends]), 0, sizeof(Onion_Friend));\n        ++onion_c->num_friends;\n    }\n\n    onion_c->friends_list[index].status = 1;\n    memcpy(onion_c->friends_list[index].real_public_key, public_key, crypto_box_PUBLICKEYBYTES);\n    crypto_box_keypair(onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key);\n    return index;\n}\n\n/* Delete a friend.\n *\n * return -1 on failure.\n * return the deleted friend number on success.\n */\nint onion_delfriend(Onion_Client *onion_c, int friend_num)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    //if (onion_c->friends_list[friend_num].know_dht_public_key)\n    //    DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, 0);\n\n    sodium_memzero(&(onion_c->friends_list[friend_num]), sizeof(Onion_Friend));\n    unsigned int i;\n\n    for (i = onion_c->num_friends; i != 0; --i) {\n        if (onion_c->friends_list[i - 1].status != 0)\n            break;\n    }\n\n    if (onion_c->num_friends != i) {\n        onion_c->num_friends = i;\n        realloc_onion_friends(onion_c, onion_c->num_friends);\n    }\n\n    return friend_num;\n}\n\n/* Set the function for this friend that will be callbacked with object and number\n * when that friends gives us one of the TCP relays he is connected to.\n *\n * object and number will be passed as argument to this function.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object,\n                           uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    onion_c->friends_list[friend_num].tcp_relay_node_callback = tcp_relay_node_callback;\n    onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object;\n    onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number;\n    return 0;\n}\n\n/* Set the function for this friend that will be callbacked with object and number\n * when that friend gives us his DHT temporary public key.\n *\n * object and number will be passed as argument to this function.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number,\n                          const uint8_t *dht_public_key), void *object, uint32_t number)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    onion_c->friends_list[friend_num].dht_pk_callback = function;\n    onion_c->friends_list[friend_num].dht_pk_callback_object = object;\n    onion_c->friends_list[friend_num].dht_pk_callback_number = number;\n    return 0;\n}\n\n/* Set a friends DHT public key.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    if (onion_c->friends_list[friend_num].status == 0)\n        return -1;\n\n    if (onion_c->friends_list[friend_num].know_dht_public_key) {\n        if (public_key_cmp(dht_key, onion_c->friends_list[friend_num].dht_public_key) == 0) {\n            return -1;\n        }\n\n        onion_c->friends_list[friend_num].know_dht_public_key = 0;\n    }\n\n    onion_c->friends_list[friend_num].last_seen = unix_time();\n    onion_c->friends_list[friend_num].know_dht_public_key = 1;\n    memcpy(onion_c->friends_list[friend_num].dht_public_key, dht_key, crypto_box_PUBLICKEYBYTES);\n\n    return 0;\n}\n\n/* Copy friends DHT public key into dht_key.\n *\n * return 0 on failure (no key copied).\n * return 1 on success (key copied).\n */\nunsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return 0;\n\n    if (onion_c->friends_list[friend_num].status == 0)\n        return 0;\n\n    if (!onion_c->friends_list[friend_num].know_dht_public_key)\n        return 0;\n\n    memcpy(dht_key, onion_c->friends_list[friend_num].dht_public_key, crypto_box_PUBLICKEYBYTES);\n    return 1;\n}\n\n/* Get the ip of friend friendnum and put it in ip_port\n *\n *  return -1, -- if public_key does NOT refer to a friend\n *  return  0, -- if public_key refers to a friend and we failed to find the friend (yet)\n *  return  1, ip if public_key refers to a friend and we found him\n *\n */\nint onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port)\n{\n    uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];\n\n    if (onion_getfriend_DHT_pubkey(onion_c, friend_num, dht_public_key) == 0)\n        return -1;\n\n    return DHT_getfriendip(onion_c->dht, dht_public_key, ip_port);\n}\n\n\n/* Set if friend is online or not.\n * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online.\n *\n * is_online 1 means friend is online.\n * is_online 0 means friend is offline\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_online)\n{\n    if ((uint32_t)friend_num >= onion_c->num_friends)\n        return -1;\n\n    if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1)\n        onion_c->friends_list[friend_num].last_seen = unix_time();\n\n    onion_c->friends_list[friend_num].is_online = is_online;\n\n    /* This should prevent some clock related issues */\n    if (!is_online) {\n        onion_c->friends_list[friend_num].last_noreplay = 0;\n        onion_c->friends_list[friend_num].run_count = 0;\n    }\n\n    return 0;\n}\n\nstatic void populate_path_nodes(Onion_Client *onion_c)\n{\n    Node_format nodes_list[MAX_FRIEND_CLIENTS];\n\n    unsigned int num_nodes = randfriends_nodes(onion_c->dht, nodes_list, MAX_FRIEND_CLIENTS);\n\n    unsigned int i;\n\n    for (i = 0; i < num_nodes; ++i) {\n        onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key);\n    }\n}\n\nstatic void populate_path_nodes_tcp(Onion_Client *onion_c)\n{\n    Node_format nodes_list[MAX_SENT_NODES];\n\n    unsigned int num_nodes = copy_connected_tcp_relays(onion_c->c, nodes_list, MAX_SENT_NODES);;\n    unsigned int i;\n\n    for (i = 0; i < num_nodes; ++i) {\n        onion_add_bs_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key);\n    }\n}\n\n#define ANNOUNCE_FRIEND (ONION_NODE_PING_INTERVAL * 6)\n#define ANNOUNCE_FRIEND_BEGINNING 3\n#define FRIEND_ONION_NODE_TIMEOUT (ONION_NODE_TIMEOUT * 6)\n\n#define RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING 17\n\nstatic void do_friend(Onion_Client *onion_c, uint16_t friendnum)\n{\n    if (friendnum >= onion_c->num_friends)\n        return;\n\n    if (onion_c->friends_list[friendnum].status == 0)\n        return;\n\n    unsigned int interval = ANNOUNCE_FRIEND;\n\n    if (onion_c->friends_list[friendnum].run_count < RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING)\n        interval = ANNOUNCE_FRIEND_BEGINNING;\n\n    unsigned int i, count = 0;\n    Onion_Node *list_nodes = onion_c->friends_list[friendnum].clients_list;\n\n    if (!onion_c->friends_list[friendnum].is_online) {\n        for (i = 0; i < MAX_ONION_CLIENTS; ++i) {\n            if (is_timeout(list_nodes[i].timestamp, FRIEND_ONION_NODE_TIMEOUT))\n                continue;\n\n            ++count;\n\n\n            if (list_nodes[i].last_pinged == 0) {\n                list_nodes[i].last_pinged = unix_time();\n                continue;\n            }\n\n            if (is_timeout(list_nodes[i].last_pinged, interval)) {\n                if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].public_key, 0, ~0) == 0) {\n                    list_nodes[i].last_pinged = unix_time();\n                }\n            }\n        }\n\n        if (count != MAX_ONION_CLIENTS) {\n            unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;\n\n            unsigned int n = num_nodes;\n\n            if (num_nodes > (MAX_ONION_CLIENTS / 2))\n                n = (MAX_ONION_CLIENTS / 2);\n\n            if (num_nodes != 0) {\n                unsigned int j;\n\n                for (j = 0; j < n; ++j) {\n                    unsigned int num = rand() % num_nodes;\n                    client_send_announce_request(onion_c, friendnum + 1, onion_c->path_nodes[num].ip_port,\n                                                 onion_c->path_nodes[num].public_key, 0, ~0);\n                }\n\n                ++onion_c->friends_list[friendnum].run_count;\n            }\n        } else {\n            ++onion_c->friends_list[friendnum].run_count;\n        }\n\n        /* send packets to friend telling them our DHT public key. */\n        if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_onion_sent, ONION_DHTPK_SEND_INTERVAL))\n            if (send_dhtpk_announce(onion_c, friendnum, 0) >= 1)\n                onion_c->friends_list[friendnum].last_dht_pk_onion_sent = unix_time();\n\n        if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_dht_sent, DHT_DHTPK_SEND_INTERVAL))\n            if (send_dhtpk_announce(onion_c, friendnum, 1) >= 1)\n                onion_c->friends_list[friendnum].last_dht_pk_dht_sent = unix_time();\n\n    }\n}\n\n\n/* Function to call when onion data packet with contents beginning with byte is received. */\nvoid oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object)\n{\n    onion_c->Onion_Data_Handlers[byte].function = cb;\n    onion_c->Onion_Data_Handlers[byte].object = object;\n}\n\n#define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 3\n#define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL\n\nstatic void do_announce(Onion_Client *onion_c)\n{\n    unsigned int i, count = 0;\n    Onion_Node *list_nodes = onion_c->clients_announce_list;\n\n    for (i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) {\n        if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT))\n            continue;\n\n        ++count;\n\n        /* Don't announce ourselves the first time this is run to new peers */\n        if (list_nodes[i].last_pinged == 0) {\n            list_nodes[i].last_pinged = 1;\n            continue;\n        }\n\n        unsigned int interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED;\n\n        if (list_nodes[i].is_stored && path_exists(&onion_c->onion_paths_self, list_nodes[i].path_used)) {\n            interval = ANNOUNCE_INTERVAL_ANNOUNCED;\n        }\n\n        if (is_timeout(list_nodes[i].last_pinged, interval)) {\n            if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].public_key,\n                                             list_nodes[i].ping_id, list_nodes[i].path_used) == 0) {\n                list_nodes[i].last_pinged = unix_time();\n            }\n        }\n    }\n\n    if (count != MAX_ONION_CLIENTS_ANNOUNCE) {\n        unsigned int num_nodes;\n        Node_format *path_nodes;\n\n        if (rand() % 2 == 0 || onion_c->path_nodes_index == 0) {\n            num_nodes = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : MAX_PATH_NODES;\n            path_nodes = onion_c->path_nodes_bs;\n        } else {\n            num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES;\n            path_nodes = onion_c->path_nodes;\n        }\n\n        if (count < (uint32_t)rand() % MAX_ONION_CLIENTS_ANNOUNCE) {\n            if (num_nodes != 0) {\n                for (i = 0; i < (MAX_ONION_CLIENTS_ANNOUNCE / 2); ++i) {\n                    unsigned int num = rand() % num_nodes;\n                    client_send_announce_request(onion_c, 0, path_nodes[num].ip_port, path_nodes[num].public_key, 0, ~0);\n                }\n            }\n        }\n    }\n}\n\n/*  return 0 if we are not connected to the network.\n *  return 1 if we are.\n */\nstatic int onion_isconnected(const Onion_Client *onion_c)\n{\n    unsigned int i, num = 0, announced = 0;\n\n    if (is_timeout(onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT))\n        return 0;\n\n    if (onion_c->path_nodes_index == 0)\n        return 0;\n\n    for (i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) {\n        if (!is_timeout(onion_c->clients_announce_list[i].timestamp, ONION_NODE_TIMEOUT)) {\n            ++num;\n\n            if (onion_c->clients_announce_list[i].is_stored) {\n                ++announced;\n            }\n        }\n    }\n\n    unsigned int pnodes = onion_c->path_nodes_index;\n\n    if (pnodes > MAX_ONION_CLIENTS_ANNOUNCE) {\n        pnodes = MAX_ONION_CLIENTS_ANNOUNCE;\n    }\n\n    /* Consider ourselves online if we are announced to half or more nodes\n      we are connected to */\n    if (num && announced) {\n        if ((num / 2) <= announced && (pnodes / 2) <= num)\n            return 1;\n    }\n\n    return 0;\n}\n\n#define ONION_CONNECTION_SECONDS 3\n\n/*  return 0 if we are not connected to the network.\n *  return 1 if we are connected with TCP only.\n *  return 2 if we are also connected with UDP.\n */\nunsigned int onion_connection_status(const Onion_Client *onion_c)\n{\n    if (onion_c->onion_connected >= ONION_CONNECTION_SECONDS) {\n        if (onion_c->UDP_connected) {\n            return 2;\n        } else {\n            return 1;\n        }\n    }\n\n    return 0;\n}\n\nvoid do_onion_client(Onion_Client *onion_c)\n{\n    unsigned int i;\n\n    if (onion_c->last_run == unix_time())\n        return;\n\n    if (is_timeout(onion_c->first_run, ONION_CONNECTION_SECONDS)) {\n        populate_path_nodes(onion_c);\n        do_announce(onion_c);\n    }\n\n    if (onion_isconnected(onion_c)) {\n        if (onion_c->onion_connected < ONION_CONNECTION_SECONDS * 2) {\n            ++onion_c->onion_connected;\n        }\n\n    } else {\n        populate_path_nodes_tcp(onion_c);\n\n        if (onion_c->onion_connected != 0) {\n            --onion_c->onion_connected;\n        }\n    }\n\n    _Bool UDP_connected = DHT_non_lan_connected(onion_c->dht);\n\n    if (is_timeout(onion_c->first_run, ONION_CONNECTION_SECONDS * 2)) {\n        set_tcp_onion_status(onion_c->c->tcp_c, !UDP_connected);\n    }\n\n    onion_c->UDP_connected = UDP_connected\n                             || get_random_tcp_onion_conn_number(onion_c->c->tcp_c) == -1; /* Check if connected to any TCP relays. */\n\n    if (onion_connection_status(onion_c)) {\n        for (i = 0; i < onion_c->num_friends; ++i) {\n            do_friend(onion_c, i);\n        }\n    }\n\n    if (onion_c->last_run == 0) {\n        onion_c->first_run = unix_time();\n    }\n\n    onion_c->last_run = unix_time();\n}\n\nOnion_Client *new_onion_client(Net_Crypto *c)\n{\n    if (c == NULL)\n        return NULL;\n\n    Onion_Client *onion_c = calloc(1, sizeof(Onion_Client));\n\n    if (onion_c == NULL)\n        return NULL;\n\n    if (ping_array_init(&onion_c->announce_ping_array, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT) != 0) {\n        free(onion_c);\n        return NULL;\n    }\n\n    onion_c->dht = c->dht;\n    onion_c->net = c->dht->net;\n    onion_c->c = c;\n    new_symmetric_key(onion_c->secret_symmetric_key);\n    crypto_box_keypair(onion_c->temp_public_key, onion_c->temp_secret_key);\n    networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c);\n    networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c);\n    oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, &handle_dhtpk_announce, onion_c);\n    cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, &handle_dht_dhtpk, onion_c);\n    set_onion_packet_tcp_connection_callback(onion_c->c->tcp_c, &handle_tcp_onion, onion_c);\n\n    return onion_c;\n}\n\nvoid kill_onion_client(Onion_Client *onion_c)\n{\n    if (onion_c == NULL)\n        return;\n\n    ping_array_free_all(&onion_c->announce_ping_array);\n    realloc_onion_friends(onion_c, 0);\n    networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL);\n    networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL);\n    oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, NULL, NULL);\n    cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, NULL, NULL);\n    set_onion_packet_tcp_connection_callback(onion_c->c->tcp_c, NULL, NULL);\n    sodium_memzero(onion_c, sizeof(Onion_Client));\n    free(onion_c);\n}\n\n"
  },
  {
    "path": "toxcore/onion_client.h",
    "content": "/*\n* onion_client.h -- Implementation of the client part of docs/Prevent_Tracking.txt\n*                   (The part that uses the onion stuff to connect to the friend)\n*\n*  Copyright (C) 2013 Tox project All Rights Reserved.\n*\n*  This file is part of Tox.\n*\n*  Tox is free software: you can redistribute it and/or modify\n*  it under the terms of the GNU General Public License as published by\n*  the Free Software Foundation, either version 3 of the License, or\n*  (at your option) any later version.\n*\n*  Tox is distributed in the hope that it will be useful,\n*  but WITHOUT ANY WARRANTY; without even the implied warranty of\n*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n*  GNU General Public License for more details.\n*\n*  You should have received a copy of the GNU General Public License\n*  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n*\n*/\n\n#ifndef ONION_CLIENT_H\n#define ONION_CLIENT_H\n\n#include \"onion_announce.h\"\n#include \"net_crypto.h\"\n#include \"ping_array.h\"\n\n#define MAX_ONION_CLIENTS 8\n#define MAX_ONION_CLIENTS_ANNOUNCE 12 /* Number of nodes to announce ourselves to. */\n#define ONION_NODE_PING_INTERVAL 15\n#define ONION_NODE_TIMEOUT (ONION_NODE_PING_INTERVAL * 3)\n\n/* The interval in seconds at which to tell our friends where we are */\n#define ONION_DHTPK_SEND_INTERVAL 30\n#define DHT_DHTPK_SEND_INTERVAL 20\n\n#define NUMBER_ONION_PATHS 6\n\n/* The timeout the first time the path is added and\n   then for all the next consecutive times */\n#define ONION_PATH_FIRST_TIMEOUT 4\n#define ONION_PATH_TIMEOUT 10\n#define ONION_PATH_MAX_LIFETIME 1200\n#define ONION_PATH_MAX_NO_RESPONSE_USES 4\n\n#define MAX_STORED_PINGED_NODES 9\n#define MIN_NODE_PING_TIME 10\n\n#define MAX_PATH_NODES 32\n\n/* If no packets are received within that interval tox will\n * be considered offline.\n */\n#define ONION_OFFLINE_TIMEOUT (ONION_NODE_PING_INTERVAL * 1.25)\n\n/* Onion data packet ids. */\n#define ONION_DATA_FRIEND_REQ CRYPTO_PACKET_FRIEND_REQ\n#define ONION_DATA_DHTPK CRYPTO_PACKET_DHTPK\n\ntypedef struct {\n    uint8_t     public_key[crypto_box_PUBLICKEYBYTES];\n    IP_Port     ip_port;\n    uint8_t     ping_id[ONION_PING_ID_SIZE];\n    uint8_t     data_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t     is_stored;\n\n    uint64_t    timestamp;\n\n    uint64_t    last_pinged;\n\n    uint32_t    path_used;\n} Onion_Node;\n\ntypedef struct {\n    Onion_Path paths[NUMBER_ONION_PATHS];\n    uint64_t last_path_success[NUMBER_ONION_PATHS];\n    uint64_t last_path_used[NUMBER_ONION_PATHS];\n    uint64_t path_creation_time[NUMBER_ONION_PATHS];\n    /* number of times used without success. */\n    unsigned int last_path_used_times[NUMBER_ONION_PATHS];\n} Onion_Client_Paths;\n\ntypedef struct {\n    uint8_t     public_key[crypto_box_PUBLICKEYBYTES];\n    uint64_t    timestamp;\n} Last_Pinged;\n\ntypedef struct {\n    uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/\n    uint8_t is_online; /* Set by the onion_set_friend_status function. */\n\n    uint8_t know_dht_public_key; /* 0 if we don't know the dht public key of the other, 1 if we do. */\n    uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t real_public_key[crypto_box_PUBLICKEYBYTES];\n\n    Onion_Node clients_list[MAX_ONION_CLIENTS];\n    uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];\n\n    uint64_t last_dht_pk_onion_sent;\n    uint64_t last_dht_pk_dht_sent;\n\n    uint64_t last_noreplay;\n\n    uint64_t last_seen;\n\n    Last_Pinged last_pinged[MAX_STORED_PINGED_NODES];\n    uint8_t last_pinged_index;\n\n    int (*tcp_relay_node_callback)(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key);\n    void *tcp_relay_node_callback_object;\n    uint32_t tcp_relay_node_callback_number;\n\n    void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key);\n    void *dht_pk_callback_object;\n    uint32_t dht_pk_callback_number;\n\n    uint32_t run_count;\n} Onion_Friend;\n\ntypedef int (*oniondata_handler_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data,\n        uint16_t len);\n\ntypedef struct {\n    DHT     *dht;\n    Net_Crypto *c;\n    Networking_Core *net;\n    Onion_Friend    *friends_list;\n    uint16_t       num_friends;\n\n    Onion_Node clients_announce_list[MAX_ONION_CLIENTS_ANNOUNCE];\n\n    Onion_Client_Paths onion_paths_self;\n    Onion_Client_Paths onion_paths_friends;\n\n    uint8_t secret_symmetric_key[crypto_box_KEYBYTES];\n    uint64_t last_run, first_run;\n\n    uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];\n\n    Last_Pinged last_pinged[MAX_STORED_PINGED_NODES];\n\n    Node_format path_nodes[MAX_PATH_NODES];\n    uint16_t path_nodes_index;\n\n    Node_format path_nodes_bs[MAX_PATH_NODES];\n    uint16_t path_nodes_index_bs;\n\n    Ping_Array announce_ping_array;\n    uint8_t last_pinged_index;\n    struct {\n        oniondata_handler_callback function;\n        void *object;\n    } Onion_Data_Handlers[256];\n\n    uint64_t last_packet_recv;\n\n    unsigned int onion_connected;\n    _Bool UDP_connected;\n} Onion_Client;\n\n\n/* Add a node to the path_nodes bootstrap array.\n *\n * return -1 on failure\n * return 0 on success\n */\nint onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key);\n\n/* Put up to max_num nodes in nodes.\n *\n * return the number of nodes.\n */\nuint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num);\n\n/* Add a friend who we want to connect to.\n *\n * return -1 on failure.\n * return the friend number on success or if the friend was already added.\n */\nint onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key);\n\n/* Add a friend who we want to connect to.\n *\n * return -1 on failure.\n * return the friend number on success.\n */\nint onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key);\n\n/* Delete a friend.\n *\n * return -1 on failure.\n * return the deleted friend number on success.\n */\nint onion_delfriend(Onion_Client *onion_c, int friend_num);\n\n/* Set if friend is online or not.\n * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online.\n *\n * is_online 1 means friend is online.\n * is_online 0 means friend is offline\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_online);\n\n/* Get the ip of friend friendnum and put it in ip_port\n *\n *  return -1, -- if public_key does NOT refer to a friend\n *  return  0, -- if public_key refers to a friend and we failed to find the friend (yet)\n *  return  1, ip if public_key refers to a friend and we found him\n *\n */\nint onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port);\n\n/* Set the function for this friend that will be callbacked with object and number\n * when that friends gives us one of the TCP relays he is connected to.\n *\n * object and number will be passed as argument to this function.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object,\n                           uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number);\n\n\n/* Set the function for this friend that will be callbacked with object and number\n * when that friend gives us his DHT temporary public key.\n *\n * object and number will be passed as argument to this function.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number,\n                          const uint8_t *dht_public_key), void *object, uint32_t number);\n\n/* Set a friends DHT public key.\n * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to\n * the other peer.\n *\n * return -1 on failure.\n * return 0 on success.\n */\nint onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key);\n\n/* Copy friends DHT public key into dht_key.\n *\n * return 0 on failure (no key copied).\n * return 1 on success (key copied).\n */\nunsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key);\n\n#define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)\n#define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE)\n\n/* Send data of length length to friendnum.\n * Maximum length of data is ONION_CLIENT_MAX_DATA_SIZE.\n * This data will be received by the friend using the Onion_Data_Handlers callbacks.\n *\n * Even if this function succeeds, the friend might not receive any data.\n *\n * return the number of packets sent on success\n * return -1 on failure.\n */\nint send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length);\n\n/* Function to call when onion data packet with contents beginning with byte is received. */\nvoid oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object);\n\nvoid do_onion_client(Onion_Client *onion_c);\n\nOnion_Client *new_onion_client(Net_Crypto *c);\n\nvoid kill_onion_client(Onion_Client *onion_c);\n\n\n/*  return 0 if we are not connected to the network.\n *  return 1 if we are connected with TCP only.\n *  return 2 if we are also connected with UDP.\n */\nunsigned int onion_connection_status(const Onion_Client *onion_c);\n\n#endif\n"
  },
  {
    "path": "toxcore/ping.c",
    "content": "/*\n * ping.c -- Buffered pinging using cyclic arrays.\n *\n * This file is donated to the Tox Project.\n * Copyright 2013  plutooo\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <stdint.h>\n\n#include \"DHT.h\"\n#include \"ping.h\"\n\n#include \"network.h\"\n#include \"util.h\"\n#include \"ping_array.h\"\n\n#define PING_NUM_MAX 512\n\n/* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */\n#define MAX_TO_PING 32\n\n/* Ping newly announced nodes to ping per TIME_TO_PING seconds*/\n#define TIME_TO_PING 2\n\n\nstruct PING {\n    DHT *dht;\n\n    Ping_Array  ping_array;\n    Node_format to_ping[MAX_TO_PING];\n    uint64_t    last_to_ping;\n};\n\n\n#define PING_PLAIN_SIZE (1 + sizeof(uint64_t))\n#define DHT_PING_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + PING_PLAIN_SIZE + crypto_box_MACBYTES)\n#define PING_DATA_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(IP_Port))\n\nint send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key)\n{\n    uint8_t   pk[DHT_PING_SIZE];\n    int       rc;\n    uint64_t  ping_id;\n\n    if (id_equal(public_key, ping->dht->self_public_key))\n        return 1;\n\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n\n    // generate key to encrypt ping_id with recipient privkey\n    DHT_get_shared_key_sent(ping->dht, shared_key, public_key);\n    // Generate random ping_id.\n    uint8_t data[PING_DATA_SIZE];\n    id_copy(data, public_key);\n    memcpy(data + crypto_box_PUBLICKEYBYTES, &ipp, sizeof(IP_Port));\n    ping_id = ping_array_add(&ping->ping_array, data, sizeof(data));\n\n    if (ping_id == 0)\n        return 1;\n\n    uint8_t ping_plain[PING_PLAIN_SIZE];\n    ping_plain[0] = NET_PACKET_PING_REQUEST;\n    memcpy(ping_plain + 1, &ping_id, sizeof(ping_id));\n\n    pk[0] = NET_PACKET_PING_REQUEST;\n    id_copy(pk + 1, ping->dht->self_public_key);     // Our pubkey\n    new_nonce(pk + 1 + crypto_box_PUBLICKEYBYTES); // Generate new nonce\n\n\n    rc = encrypt_data_symmetric(shared_key,\n                                pk + 1 + crypto_box_PUBLICKEYBYTES,\n                                ping_plain, sizeof(ping_plain),\n                                pk + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);\n\n    if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES)\n        return 1;\n\n    return sendpacket(ping->dht->net, ipp, pk, sizeof(pk));\n}\n\nstatic int send_ping_response(PING *ping, IP_Port ipp, const uint8_t *public_key, uint64_t ping_id,\n                              uint8_t *shared_encryption_key)\n{\n    uint8_t   pk[DHT_PING_SIZE];\n    int       rc;\n\n    if (id_equal(public_key, ping->dht->self_public_key))\n        return 1;\n\n    uint8_t ping_plain[PING_PLAIN_SIZE];\n    ping_plain[0] = NET_PACKET_PING_RESPONSE;\n    memcpy(ping_plain + 1, &ping_id, sizeof(ping_id));\n\n    pk[0] = NET_PACKET_PING_RESPONSE;\n    id_copy(pk + 1, ping->dht->self_public_key);     // Our pubkey\n    new_nonce(pk + 1 + crypto_box_PUBLICKEYBYTES); // Generate new nonce\n\n    // Encrypt ping_id using recipient privkey\n    rc = encrypt_data_symmetric(shared_encryption_key,\n                                pk + 1 + crypto_box_PUBLICKEYBYTES,\n                                ping_plain, sizeof(ping_plain),\n                                pk + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES );\n\n    if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES)\n        return 1;\n\n    return sendpacket(ping->dht->net, ipp, pk, sizeof(pk));\n}\n\nstatic int handle_ping_request(void *_dht, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    DHT       *dht = _dht;\n    int        rc;\n\n    if (length != DHT_PING_SIZE)\n        return 1;\n\n    PING *ping = dht->ping;\n\n    if (id_equal(packet + 1, ping->dht->self_public_key))\n        return 1;\n\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n\n    uint8_t ping_plain[PING_PLAIN_SIZE];\n    // Decrypt ping_id\n    DHT_get_shared_key_recv(dht, shared_key, packet + 1);\n    rc = decrypt_data_symmetric(shared_key,\n                                packet + 1 + crypto_box_PUBLICKEYBYTES,\n                                packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,\n                                PING_PLAIN_SIZE + crypto_box_MACBYTES,\n                                ping_plain );\n\n    if (rc != sizeof(ping_plain))\n        return 1;\n\n    if (ping_plain[0] != NET_PACKET_PING_REQUEST)\n        return 1;\n\n    uint64_t   ping_id;\n    memcpy(&ping_id, ping_plain + 1, sizeof(ping_id));\n    // Send response\n    send_ping_response(ping, source, packet + 1, ping_id, shared_key);\n    add_to_ping(ping, packet + 1, source);\n\n    return 0;\n}\n\nstatic int handle_ping_response(void *_dht, IP_Port source, const uint8_t *packet, uint16_t length)\n{\n    DHT      *dht = _dht;\n    int       rc;\n\n    if (length != DHT_PING_SIZE)\n        return 1;\n\n    PING *ping = dht->ping;\n\n    if (id_equal(packet + 1, ping->dht->self_public_key))\n        return 1;\n\n    uint8_t shared_key[crypto_box_BEFORENMBYTES];\n\n    // generate key to encrypt ping_id with recipient privkey\n    DHT_get_shared_key_sent(ping->dht, shared_key, packet + 1);\n\n    uint8_t ping_plain[PING_PLAIN_SIZE];\n    // Decrypt ping_id\n    rc = decrypt_data_symmetric(shared_key,\n                                packet + 1 + crypto_box_PUBLICKEYBYTES,\n                                packet + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,\n                                PING_PLAIN_SIZE + crypto_box_MACBYTES,\n                                ping_plain);\n\n    if (rc != sizeof(ping_plain))\n        return 1;\n\n    if (ping_plain[0] != NET_PACKET_PING_RESPONSE)\n        return 1;\n\n    uint64_t   ping_id;\n    memcpy(&ping_id, ping_plain + 1, sizeof(ping_id));\n    uint8_t data[PING_DATA_SIZE];\n\n    if (ping_array_check(data, sizeof(data), &ping->ping_array, ping_id) != sizeof(data))\n        return 1;\n\n    if (!id_equal(packet + 1, data))\n        return 1;\n\n    IP_Port ipp;\n    memcpy(&ipp, data + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port));\n\n    if (!ipport_equal(&ipp, &source))\n        return 1;\n\n    addto_lists(dht, source, packet + 1);\n    return 0;\n}\n\n/* Check if public_key with ip_port is in the list.\n *\n * return 1 if it is.\n * return 0 if it isn't.\n */\nstatic int in_list(const Client_data *list, uint16_t length, const uint8_t *public_key, IP_Port ip_port)\n{\n    unsigned int i;\n\n    for (i = 0; i < length; ++i) {\n        if (id_equal(list[i].public_key, public_key)) {\n            const IPPTsPng *ipptp;\n\n            if (ip_port.ip.family == AF_INET) {\n                ipptp = &list[i].assoc4;\n            } else {\n                ipptp = &list[i].assoc6;\n            }\n\n            if (!is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT) && ipport_equal(&ipptp->ip_port, &ip_port))\n                return 1;\n        }\n    }\n\n    return 0;\n}\n\n/* Add nodes to the to_ping list.\n * All nodes in this list are pinged every TIME_TO_PING seconds\n * and are then removed from the list.\n * If the list is full the nodes farthest from our public_key are replaced.\n * The purpose of this list is to enable quick integration of new nodes into the\n * network while preventing amplification attacks.\n *\n *  return 0 if node was added.\n *  return -1 if node was not added.\n */\nint add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port)\n{\n    if (!ip_isset(&ip_port.ip))\n        return -1;\n\n    if (!node_addable_to_close_list(ping->dht, public_key, ip_port))\n        return -1;\n\n    if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, public_key, ip_port))\n        return -1;\n\n    IP_Port temp;\n\n    if (DHT_getfriendip(ping->dht, public_key, &temp) == 0) {\n        send_ping_request(ping, ip_port, public_key);\n        return -1;\n    }\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_TO_PING; ++i) {\n        if (!ip_isset(&ping->to_ping[i].ip_port.ip)) {\n            memcpy(ping->to_ping[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);\n            ipport_copy(&ping->to_ping[i].ip_port, &ip_port);\n            return 0;\n        }\n\n        if (public_key_cmp(ping->to_ping[i].public_key, public_key) == 0) {\n            return -1;\n        }\n    }\n\n    if (add_to_list(ping->to_ping, MAX_TO_PING, public_key, ip_port, ping->dht->self_public_key))\n        return 0;\n\n    return -1;\n}\n\n\n/* Ping all the valid nodes in the to_ping list every TIME_TO_PING seconds.\n * This function must be run at least once every TIME_TO_PING seconds.\n */\nvoid do_to_ping(PING *ping)\n{\n    if (!is_timeout(ping->last_to_ping, TIME_TO_PING))\n        return;\n\n    if (!ip_isset(&ping->to_ping[0].ip_port.ip))\n        return;\n\n    unsigned int i;\n\n    for (i = 0; i < MAX_TO_PING; ++i) {\n        if (!ip_isset(&ping->to_ping[i].ip_port.ip))\n            break;\n\n        if (!node_addable_to_close_list(ping->dht, ping->to_ping[i].public_key, ping->to_ping[i].ip_port))\n            continue;\n\n        send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].public_key);\n        ip_reset(&ping->to_ping[i].ip_port.ip);\n    }\n\n    if (i != 0)\n        ping->last_to_ping = unix_time();\n}\n\n\nPING *new_ping(DHT *dht)\n{\n    PING *ping = calloc(1, sizeof(PING));\n\n    if (ping == NULL)\n        return NULL;\n\n    if (ping_array_init(&ping->ping_array, PING_NUM_MAX, PING_TIMEOUT) != 0) {\n        free(ping);\n        return NULL;\n    }\n\n    ping->dht = dht;\n    networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, &handle_ping_request, dht);\n    networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, dht);\n\n    return ping;\n}\n\nvoid kill_ping(PING *ping)\n{\n    networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, NULL, NULL);\n    networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, NULL, NULL);\n    ping_array_free_all(&ping->ping_array);\n\n    free(ping);\n}\n"
  },
  {
    "path": "toxcore/ping.h",
    "content": "/*\n * ping.h -- Buffered pinging using cyclic arrays.\n *\n * This file is donated to the Tox Project.\n * Copyright 2013  plutooo\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n */\n#ifndef __PING_H__\n#define __PING_H__\n\ntypedef struct PING PING;\n\n/* Add nodes to the to_ping list.\n * All nodes in this list are pinged every TIME_TOPING seconds\n * and are then removed from the list.\n * If the list is full the nodes farthest from our public_key are replaced.\n * The purpose of this list is to enable quick integration of new nodes into the\n * network while preventing amplification attacks.\n *\n *  return 0 if node was added.\n *  return -1 if node was not added.\n */\nint add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port);\nvoid do_to_ping(PING *ping);\n\nPING *new_ping(DHT *dht);\nvoid kill_ping(PING *ping);\n\nint send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key);\n\n#endif /* __PING_H__ */\n"
  },
  {
    "path": "toxcore/ping_array.c",
    "content": "/* ping_array.c\n *\n * Implementation of an efficient array to store that we pinged something.\n *\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"ping_array.h\"\n#include \"crypto_core.h\"\n#include \"util.h\"\n\nstatic void clear_entry(Ping_Array *array, uint32_t index)\n{\n    free(array->entries[index].data);\n    array->entries[index].data = NULL;\n    array->entries[index].length =\n        array->entries[index].time =\n            array->entries[index].ping_id = 0;\n}\n\n/* Clear timed out entries.\n */\nstatic void ping_array_clear_timedout(Ping_Array *array)\n{\n    while (array->last_deleted != array->last_added) {\n        uint32_t index = array->last_deleted % array->total_size;\n\n        if (!is_timeout(array->entries[index].time, array->timeout))\n            break;\n\n        clear_entry(array, index);\n        ++array->last_deleted;\n    }\n}\n\n/* Add a data with length to the Ping_Array list and return a ping_id.\n *\n * return ping_id on success.\n * return 0 on failure.\n */\nuint64_t ping_array_add(Ping_Array *array, const uint8_t *data, uint32_t length)\n{\n    ping_array_clear_timedout(array);\n    uint32_t index = array->last_added % array->total_size;\n\n    if (array->entries[index].data != NULL) {\n        array->last_deleted = array->last_added - array->total_size;\n        clear_entry(array, index);\n    }\n\n    array->entries[index].data = malloc(length);\n\n    if (array->entries[index].data == NULL)\n        return 0;\n\n    memcpy(array->entries[index].data, data, length);\n    array->entries[index].length = length;\n    array->entries[index].time = unix_time();\n    ++array->last_added;\n    uint64_t ping_id = random_64b();\n    ping_id /= array->total_size;\n    ping_id *= array->total_size;\n    ping_id += index;\n\n    if (ping_id == 0)\n        ping_id += array->total_size;\n\n    array->entries[index].ping_id = ping_id;\n    return ping_id;\n}\n\n\n/* Check if ping_id is valid and not timed out.\n *\n * On success, copies the data into data of length,\n *\n * return length of data copied on success.\n * return -1 on failure.\n */\nint ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id)\n{\n    if (ping_id == 0)\n        return -1;\n\n    uint32_t index = ping_id % array->total_size;\n\n    if (array->entries[index].ping_id != ping_id)\n        return -1;\n\n    if (is_timeout(array->entries[index].time, array->timeout))\n        return -1;\n\n    if (array->entries[index].length > length)\n        return -1;\n\n    if (array->entries[index].data == NULL)\n        return -1;\n\n    memcpy(data, array->entries[index].data, array->entries[index].length);\n    uint32_t len = array->entries[index].length;\n    clear_entry(array, index);\n    return len;\n}\n\n/* Initialize a Ping_Array.\n * size represents the total size of the array and should be a power of 2.\n * timeout represents the maximum timeout in seconds for the entry.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout)\n{\n    if (size == 0 || timeout == 0 || empty_array == NULL)\n        return -1;\n\n    empty_array->entries = calloc(size, sizeof(Ping_Array_Entry));\n\n    if (empty_array->entries == NULL)\n        return -1;\n\n    empty_array->last_deleted = empty_array->last_added = 0;\n    empty_array->total_size = size;\n    empty_array->timeout = timeout;\n    return 0;\n}\n\n/* Free all the allocated memory in a Ping_Array.\n */\nvoid ping_array_free_all(Ping_Array *array)\n{\n    while (array->last_deleted != array->last_added) {\n        uint32_t index = array->last_deleted % array->total_size;\n        clear_entry(array, index);\n        ++array->last_deleted;\n    }\n\n    free(array->entries);\n    array->entries = NULL;\n}\n\n"
  },
  {
    "path": "toxcore/ping_array.h",
    "content": "/* ping_array.h\n *\n * Implementation of an efficient array to store that we pinged something.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n#ifndef PING_ARRAY_H\n#define PING_ARRAY_H\n\n#include \"network.h\"\n\ntypedef struct {\n    void *data;\n    uint32_t length;\n    uint64_t time;\n    uint64_t ping_id;\n} Ping_Array_Entry;\n\n\ntypedef struct {\n    Ping_Array_Entry *entries;\n\n    uint32_t last_deleted; /* number representing the next entry to be deleted. */\n    uint32_t last_added; /* number representing the last entry to be added. */\n    uint32_t total_size; /* The length of entries */\n    uint32_t timeout; /* The timeout after which entries are cleared. */\n} Ping_Array;\n\n\n/* Add a data with length to the Ping_Array list and return a ping_id.\n *\n * return ping_id on success.\n * return 0 on failure.\n */\nuint64_t ping_array_add(Ping_Array *array, const uint8_t *data, uint32_t length);\n\n/* Check if ping_id is valid and not timed out.\n *\n * On success, copies the data into data of length,\n *\n * return length of data copied on success.\n * return -1 on failure.\n */\nint ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id);\n\n/* Initialize a Ping_Array.\n * size represents the total size of the array and should be a power of 2.\n * timeout represents the maximum timeout in seconds for the entry.\n *\n * return 0 on success.\n * return -1 on failure.\n */\nint ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout);\n\n/* Free all the allocated memory in a Ping_Array.\n */\nvoid ping_array_free_all(Ping_Array *array);\n\n#endif\n"
  },
  {
    "path": "toxcore/tox.c",
    "content": "/* tox.c\n *\n * The Tox public API.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"Messenger.h\"\n#include \"group.h\"\n#include \"logger.h\"\n\n#include \"../toxencryptsave/defines.h\"\n\n#define TOX_DEFINED\ntypedef struct Messenger Tox;\n\n#include \"tox.h\"\n\n#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}}\n\n#if TOX_HASH_LENGTH != crypto_hash_sha256_BYTES\n#error TOX_HASH_LENGTH is assumed to be equal to crypto_hash_sha256_BYTES\n#endif\n\n#if FILE_ID_LENGTH != crypto_box_KEYBYTES\n#error FILE_ID_LENGTH is assumed to be equal to crypto_box_KEYBYTES\n#endif\n\n#if TOX_FILE_ID_LENGTH != crypto_box_KEYBYTES\n#error TOX_FILE_ID_LENGTH is assumed to be equal to crypto_box_KEYBYTES\n#endif\n\n#if TOX_FILE_ID_LENGTH != TOX_HASH_LENGTH\n#error TOX_FILE_ID_LENGTH is assumed to be equal to TOX_HASH_LENGTH\n#endif\n\n#if TOX_PUBLIC_KEY_SIZE != crypto_box_PUBLICKEYBYTES\n#error TOX_PUBLIC_KEY_SIZE is assumed to be equal to crypto_box_PUBLICKEYBYTES\n#endif\n\n#if TOX_SECRET_KEY_SIZE != crypto_box_SECRETKEYBYTES\n#error TOX_SECRET_KEY_SIZE is assumed to be equal to crypto_box_SECRETKEYBYTES\n#endif\n\n#if TOX_MAX_NAME_LENGTH != MAX_NAME_LENGTH\n#error TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH\n#endif\n\n#if TOX_MAX_STATUS_MESSAGE_LENGTH != MAX_STATUSMESSAGE_LENGTH\n#error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH\n#endif\n\nuint32_t tox_version_major(void)\n{\n    return TOX_VERSION_MAJOR;\n}\n\nuint32_t tox_version_minor(void)\n{\n    return TOX_VERSION_MINOR;\n}\n\nuint32_t tox_version_patch(void)\n{\n    return TOX_VERSION_PATCH;\n}\n\nbool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)\n{\n  return (TOX_VERSION_MAJOR == major && /* Force the major version */\n            (TOX_VERSION_MINOR > minor || /* Current minor version must be newer than requested -- or -- */\n                (TOX_VERSION_MINOR == minor && TOX_VERSION_PATCH >= patch) /* the patch must be the same or newer */\n            )\n         );\n}\n\n\nvoid tox_options_default(struct Tox_Options *options)\n{\n    if (options) {\n        memset(options, 0, sizeof(struct Tox_Options));\n        options->ipv6_enabled = 1;\n        options->udp_enabled = 1;\n        options->proxy_type = TOX_PROXY_TYPE_NONE;\n    }\n}\n\nstruct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error)\n{\n    struct Tox_Options *options = calloc(sizeof(struct Tox_Options), 1);\n\n    if (options) {\n        tox_options_default(options);\n        SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK);\n        return options;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC);\n    return NULL;\n}\n\nvoid tox_options_free(struct Tox_Options *options)\n{\n    free(options);\n}\n\nTox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error)\n{\n    if (!logger_get_global())\n        logger_set_global(logger_new(LOGGER_OUTPUT_FILE, LOGGER_LEVEL, \"toxcore\"));\n\n    Messenger_Options m_options = {0};\n\n    _Bool load_savedata_sk = 0, load_savedata_tox = 0;\n\n    if (options == NULL) {\n        m_options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT;\n    } else {\n        if (options->savedata_type != TOX_SAVEDATA_TYPE_NONE) {\n            if (options->savedata_data == NULL || options->savedata_length == 0) {\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);\n                return NULL;\n            }\n        }\n\n        if (options->savedata_type == TOX_SAVEDATA_TYPE_SECRET_KEY) {\n            if (options->savedata_length != TOX_SECRET_KEY_SIZE) {\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);\n                return NULL;\n            }\n\n            load_savedata_sk = 1;\n        } else if (options->savedata_type == TOX_SAVEDATA_TYPE_TOX_SAVE) {\n            if (options->savedata_length < TOX_ENC_SAVE_MAGIC_LENGTH) {\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);\n                return NULL;\n            }\n\n            if (sodium_memcmp(options->savedata_data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) {\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED);\n                return NULL;\n            }\n\n            load_savedata_tox = 1;\n        }\n\n        m_options.ipv6enabled = options->ipv6_enabled;\n        m_options.udp_disabled = !options->udp_enabled;\n        m_options.port_range[0] = options->start_port;\n        m_options.port_range[1] = options->end_port;\n        m_options.tcp_server_port = options->tcp_port;\n\n        switch (options->proxy_type) {\n            case TOX_PROXY_TYPE_HTTP:\n                m_options.proxy_info.proxy_type = TCP_PROXY_HTTP;\n                break;\n\n            case TOX_PROXY_TYPE_SOCKS5:\n                m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5;\n                break;\n\n            case TOX_PROXY_TYPE_NONE:\n                m_options.proxy_info.proxy_type = TCP_PROXY_NONE;\n                break;\n\n            default:\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_TYPE);\n                return NULL;\n        }\n\n        if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) {\n            if (options->proxy_port == 0) {\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT);\n                return NULL;\n            }\n\n            ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled);\n\n            if (m_options.ipv6enabled)\n                m_options.proxy_info.ip_port.ip.family = AF_UNSPEC;\n\n            if (!addr_resolve_or_parse_ip(options->proxy_host, &m_options.proxy_info.ip_port.ip, NULL)) {\n                SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST);\n                //TODO: TOX_ERR_NEW_PROXY_NOT_FOUND if domain.\n                return NULL;\n            }\n\n            m_options.proxy_info.ip_port.port = htons(options->proxy_port);\n        }\n    }\n\n    unsigned int m_error;\n    Messenger *m = new_messenger(&m_options, &m_error);\n\n    if (!new_groupchats(m)) {\n        kill_messenger(m);\n\n        if (m_error == MESSENGER_ERROR_PORT) {\n            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC);\n        } else if (m_error == MESSENGER_ERROR_TCP_SERVER) {\n            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC);\n        } else {\n            SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC);\n        }\n\n        return NULL;\n    }\n\n    if (load_savedata_tox && messenger_load(m, options->savedata_data, options->savedata_length) == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT);\n    } else if (load_savedata_sk) {\n        load_secret_key(m->net_crypto, options->savedata_data);\n        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK);\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK);\n    }\n\n    return m;\n}\n\nvoid tox_kill(Tox *tox)\n{\n    Messenger *m = tox;\n    kill_groupchats(m->group_chat_object);\n    kill_messenger(m);\n    logger_kill_global();\n}\n\nsize_t tox_get_savedata_size(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return messenger_size(m);\n}\n\nvoid tox_get_savedata(const Tox *tox, uint8_t *data)\n{\n    if (data) {\n        const Messenger *m = tox;\n        messenger_save(m, data);\n    }\n}\n\nbool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error)\n{\n    if (!address || !public_key) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL);\n        return 0;\n    }\n\n    if (port == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);\n        return 0;\n    }\n\n    struct addrinfo *root, *info;\n\n    if (getaddrinfo(address, NULL, NULL, &root) != 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);\n        return 0;\n    }\n\n    info = root;\n\n    unsigned int count = 0;\n\n    do {\n        IP_Port ip_port;\n        ip_port.port = htons(port);\n        ip_port.ip.family = info->ai_family;\n\n        if (info->ai_socktype && info->ai_socktype != SOCK_DGRAM) {\n            continue;\n        }\n\n        if (info->ai_family == AF_INET) {\n            ip_port.ip.ip4.in_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;\n        } else if (info->ai_family == AF_INET6) {\n            ip_port.ip.ip6.in6_addr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;\n        } else {\n            continue;\n        }\n\n        Messenger *m = tox;\n        onion_add_bs_path_node(m->onion_c, ip_port, public_key);\n        DHT_bootstrap(m->dht, ip_port, public_key);\n        ++count;\n    } while ((info = info->ai_next));\n\n    freeaddrinfo(root);\n\n    if (count) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);\n        return 1;\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);\n        return 0;\n    }\n}\n\nbool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key,\n                       TOX_ERR_BOOTSTRAP *error)\n{\n    if (!address || !public_key) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL);\n        return 0;\n    }\n\n    if (port == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT);\n        return 0;\n    }\n\n    struct addrinfo *root, *info;\n\n    if (getaddrinfo(address, NULL, NULL, &root) != 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);\n        return 0;\n    }\n\n    info = root;\n\n    unsigned int count = 0;\n\n    do {\n        IP_Port ip_port;\n        ip_port.port = htons(port);\n        ip_port.ip.family = info->ai_family;\n\n        if (info->ai_socktype && info->ai_socktype != SOCK_STREAM) {\n            continue;\n        }\n\n        if (info->ai_family == AF_INET) {\n            ip_port.ip.ip4.in_addr = ((struct sockaddr_in *)info->ai_addr)->sin_addr;\n        } else if (info->ai_family == AF_INET6) {\n            ip_port.ip.ip6.in6_addr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;\n        } else {\n            continue;\n        }\n\n        Messenger *m = tox;\n        add_tcp_relay(m->net_crypto, ip_port, public_key);\n        ++count;\n    } while ((info = info->ai_next));\n\n    freeaddrinfo(root);\n\n    if (count) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK);\n        return 1;\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST);\n        return 0;\n    }\n}\n\nTOX_CONNECTION tox_self_get_connection_status(const Tox *tox)\n{\n    const Messenger *m = tox;\n\n    unsigned int ret = onion_connection_status(m->onion_c);\n\n    if (ret == 2) {\n        return TOX_CONNECTION_UDP;\n    } else if (ret == 1) {\n        return TOX_CONNECTION_TCP;\n    } else {\n        return TOX_CONNECTION_NONE;\n    }\n}\n\n\nvoid tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_core_connection(m, function, user_data);\n}\n\nuint32_t tox_iteration_interval(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return messenger_run_interval(m);\n}\n\nvoid tox_iterate(Tox *tox)\n{\n    Messenger *m = tox;\n    do_messenger(m);\n    do_groupchats(m->group_chat_object);\n}\n\nvoid tox_self_get_address(const Tox *tox, uint8_t *address)\n{\n    if (address) {\n        const Messenger *m = tox;\n        getaddress(m, address);\n    }\n}\n\nvoid tox_self_set_nospam(Tox *tox, uint32_t nospam)\n{\n    Messenger *m = tox;\n    set_nospam(&(m->fr), nospam);\n}\n\nuint32_t tox_self_get_nospam(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return get_nospam(&(m->fr));\n}\n\nvoid tox_self_get_public_key(const Tox *tox, uint8_t *public_key)\n{\n    const Messenger *m = tox;\n\n    if (public_key)\n        memcpy(public_key, m->net_crypto->self_public_key, crypto_box_PUBLICKEYBYTES);\n}\n\nvoid tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key)\n{\n    const Messenger *m = tox;\n\n    if (secret_key)\n        memcpy(secret_key, m->net_crypto->self_secret_key, crypto_box_SECRETKEYBYTES);\n}\n\nbool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error)\n{\n    if (!name && length != 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL);\n        return 0;\n    }\n\n    Messenger *m = tox;\n\n    if (setname(m, name, length) == 0) {\n        //TODO: function to set different per group names?\n        send_name_all_groups(m->group_chat_object);\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK);\n        return 1;\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG);\n        return 0;\n    }\n}\n\nsize_t tox_self_get_name_size(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return m_get_self_name_size(m);\n}\n\nvoid tox_self_get_name(const Tox *tox, uint8_t *name)\n{\n    if (name) {\n        const Messenger *m = tox;\n        getself_name(m, name);\n    }\n}\n\nbool tox_self_set_status_message(Tox *tox, const uint8_t *status, size_t length, TOX_ERR_SET_INFO *error)\n{\n    if (!status && length != 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL);\n        return 0;\n    }\n\n    Messenger *m = tox;\n\n    if (m_set_statusmessage(m, status, length) == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK);\n        return 1;\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG);\n        return 0;\n    }\n}\n\nsize_t tox_self_get_status_message_size(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return m_get_self_statusmessage_size(m);\n}\n\nvoid tox_self_get_status_message(const Tox *tox, uint8_t *status)\n{\n    if (status) {\n        const Messenger *m = tox;\n        m_copy_self_statusmessage(m, status);\n    }\n}\n\nvoid tox_self_set_status(Tox *tox, TOX_USER_STATUS user_status)\n{\n    Messenger *m = tox;\n    m_set_userstatus(m, user_status);\n}\n\nTOX_USER_STATUS tox_self_get_status(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return m_get_self_userstatus(m);\n}\n\nstatic void set_friend_error(int32_t ret, TOX_ERR_FRIEND_ADD *error)\n{\n    switch (ret) {\n        case FAERR_TOOLONG:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG);\n            break;\n\n        case FAERR_NOMESSAGE:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE);\n            break;\n\n        case FAERR_OWNKEY:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY);\n            break;\n\n        case FAERR_ALREADYSENT:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT);\n            break;\n\n        case FAERR_BADCHECKSUM:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM);\n            break;\n\n        case FAERR_SETNEWNOSPAM:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM);\n            break;\n\n        case FAERR_NOMEM:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC);\n            break;\n\n    }\n}\n\nuint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length,\n                        TOX_ERR_FRIEND_ADD *error)\n{\n    if (!address || !message) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL);\n        return UINT32_MAX;\n    }\n\n    Messenger *m = tox;\n    int32_t ret = m_addfriend(m, address, message, length);\n\n    if (ret >= 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);\n        return ret;\n    }\n\n    set_friend_error(ret, error);\n    return UINT32_MAX;\n}\n\nuint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error)\n{\n    if (!public_key) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL);\n        return UINT32_MAX;\n    }\n\n    Messenger *m = tox;\n    int32_t ret = m_addfriend_norequest(m, public_key);\n\n    if (ret >= 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK);\n        return ret;\n    }\n\n    set_friend_error(ret, error);\n    return UINT32_MAX;\n}\n\nbool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error)\n{\n    Messenger *m = tox;\n    int ret = m_delfriend(m, friend_number);\n\n    //TODO handle if realloc fails?\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK);\n    return 1;\n}\n\nuint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error)\n{\n    if (!public_key) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL);\n        return UINT32_MAX;\n    }\n\n    const Messenger *m = tox;\n    int32_t ret = getfriend_id(m, public_key);\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND);\n        return UINT32_MAX;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK);\n    return ret;\n}\n\nbool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key,\n                               TOX_ERR_FRIEND_GET_PUBLIC_KEY *error)\n{\n    if (!public_key) {\n        return 0;\n    }\n\n    const Messenger *m = tox;\n\n    if (get_real_pk(m, friend_number, public_key) == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK);\n    return 1;\n}\n\nbool tox_friend_exists(const Tox *tox, uint32_t friend_number)\n{\n    const Messenger *m = tox;\n    return m_friend_exists(m, friend_number);\n}\n\nuint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error)\n{\n    const Messenger *m = tox;\n    uint64_t timestamp = m_get_last_online(m, friend_number);\n\n    if (timestamp == UINT64_MAX) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND)\n        return UINT64_MAX;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_OK);\n    return timestamp;\n}\n\nsize_t tox_self_get_friend_list_size(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return count_friendlist(m);\n}\n\nvoid tox_self_get_friend_list(const Tox *tox, uint32_t *list)\n{\n    if (list) {\n        const Messenger *m = tox;\n        //TODO: size parameter?\n        copy_friendlist(m, list, tox_self_get_friend_list_size(tox));\n    }\n}\n\nsize_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)\n{\n    const Messenger *m = tox;\n    int ret = m_get_name_size(m, friend_number);\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return SIZE_MAX;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return ret;\n}\n\nbool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error)\n{\n    if (!name) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL);\n        return 0;\n    }\n\n    const Messenger *m = tox;\n    int ret = getname(m, friend_number, name);\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return 1;\n}\n\nvoid tox_callback_friend_name(Tox *tox, tox_friend_name_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_namechange(m, function, user_data);\n}\n\nsize_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)\n{\n    const Messenger *m = tox;\n    int ret = m_get_statusmessage_size(m, friend_number);\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return SIZE_MAX;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return ret;\n}\n\nbool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *message,\n                                   TOX_ERR_FRIEND_QUERY *error)\n{\n    if (!message) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL);\n        return 0;\n    }\n\n    const Messenger *m = tox;\n    //TODO: size parameter?\n    int ret = m_copy_statusmessage(m, friend_number, message, m_get_statusmessage_size(m, friend_number));\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return 1;\n}\n\nvoid tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_statusmessage(m, function, user_data);\n}\n\nTOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)\n{\n    const Messenger *m = tox;\n\n    int ret = m_get_userstatus(m, friend_number);\n\n    if (ret == USERSTATUS_INVALID) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return TOX_USER_STATUS_BUSY + 1;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return ret;\n}\n\nvoid tox_callback_friend_status(Tox *tox, tox_friend_status_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_userstatus(m, function, user_data);\n}\n\nTOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)\n{\n    const Messenger *m = tox;\n\n    int ret = m_get_friend_connectionstatus(m, friend_number);\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return TOX_CONNECTION_NONE;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return ret;\n}\n\nvoid tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_connectionstatus(m, function, user_data);\n}\n\nbool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error)\n{\n    const Messenger *m = tox;\n    int ret = m_get_istyping(m, friend_number);\n\n    if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK);\n    return !!ret;\n}\n\nvoid tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_typingchange(m, function, user_data);\n}\n\nbool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool is_typing, TOX_ERR_SET_TYPING *error)\n{\n    Messenger *m = tox;\n\n    if (m_set_usertyping(m, friend_number, is_typing) == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_OK);\n    return 1;\n}\n\nstatic void set_message_error(int ret, TOX_ERR_FRIEND_SEND_MESSAGE *error)\n{\n    switch (ret) {\n        case 0:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_OK);\n            break;\n\n        case -1:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND);\n            break;\n\n        case -2:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG);\n            break;\n\n        case -3:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED);\n            break;\n\n        case -4:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ);\n            break;\n\n        case -5:\n            /* can't happen */\n            break;\n    }\n}\n\nuint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message,\n                                 size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error)\n{\n    if (!message) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_NULL);\n        return 0;\n    }\n\n    if (!length) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY);\n        return 0;\n    }\n\n    Messenger *m = tox;\n    uint32_t message_id = 0;\n    set_message_error(m_send_message_generic(m, friend_number, type, message, length, &message_id), error);\n    return message_id;\n}\n\nvoid tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_read_receipt(m, function, user_data);\n}\n\nvoid tox_callback_friend_request(Tox *tox, tox_friend_request_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_friendrequest(m, function, user_data);\n}\n\nvoid tox_callback_friend_message(Tox *tox, tox_friend_message_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    m_callback_friendmessage(m, function, user_data);\n}\n\nbool tox_hash(uint8_t *hash, const uint8_t *data, size_t length)\n{\n    if (!hash || (length && !data)) {\n        return 0;\n    }\n\n    crypto_hash_sha256(hash, data, length);\n    return 1;\n}\n\nbool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,\n                      TOX_ERR_FILE_CONTROL *error)\n{\n    Messenger *m = tox;\n    int ret = file_control(m, friend_number, file_number, control);\n\n    if (ret == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK);\n        return 1;\n    }\n\n    switch (ret) {\n        case -1:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND);\n            return 0;\n\n        case -2:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED);\n            return 0;\n\n        case -3:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND);\n            return 0;\n\n        case -4:\n            /* can't happen */\n            return 0;\n\n        case -5:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED);\n            return 0;\n\n        case -6:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED);\n            return 0;\n\n        case -7:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED);\n            return 0;\n\n        case -8:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SENDQ);\n            return 0;\n    }\n\n    /* can't happen */\n    return 0;\n}\n\nbool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,\n                   TOX_ERR_FILE_SEEK *error)\n{\n    Messenger *m = tox;\n    int ret = file_seek(m, friend_number, file_number, position);\n\n    if (ret == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK);\n        return 1;\n    }\n\n    switch (ret) {\n        case -1:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND);\n            return 0;\n\n        case -2:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED);\n            return 0;\n\n        case -3:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_NOT_FOUND);\n            return 0;\n\n        case -4:\n        case -5:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_DENIED);\n            return 0;\n\n        case -6:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_INVALID_POSITION);\n            return 0;\n\n        case -8:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_SENDQ);\n            return 0;\n    }\n\n    /* can't happen */\n    return 0;\n}\n\nvoid tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    callback_file_control(m, function, user_data);\n}\n\nbool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id,\n                          TOX_ERR_FILE_GET *error)\n{\n    if (!file_id) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NULL);\n        return 0;\n    }\n\n    const Messenger *m = tox;\n    int ret = file_get_id(m, friend_number, file_number, file_id);\n\n    if (ret == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK);\n        return 1;\n    } else if (ret == -1) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND);\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND);\n    }\n\n    return 0;\n}\n\nuint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id,\n                       const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error)\n{\n    if (filename_length && !filename) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL);\n        return UINT32_MAX;\n    }\n\n    uint8_t f_id[FILE_ID_LENGTH];\n\n    if (!file_id) {\n        /* Tox keys are 32 bytes like FILE_ID_LENGTH. */\n        new_symmetric_key(f_id);\n        file_id = f_id;\n    }\n\n    Messenger *m = tox;\n    long int file_num = new_filesender(m, friend_number, kind, file_size, file_id, filename, filename_length);\n\n    if (file_num >= 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK);\n        return file_num;\n    }\n\n    switch (file_num) {\n        case -1:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND);\n            return UINT32_MAX;\n\n        case -2:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG);\n            return UINT32_MAX;\n\n        case -3:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY);\n            return UINT32_MAX;\n\n        case -4:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED);\n            return UINT32_MAX;\n    }\n\n    /* can't happen */\n    return UINT32_MAX;\n}\n\nbool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data,\n                         size_t length, TOX_ERR_FILE_SEND_CHUNK *error)\n{\n    Messenger *m = tox;\n    int ret = file_data(m, friend_number, file_number, position, data, length);\n\n    if (ret == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK);\n        return 1;\n    }\n\n    switch (ret) {\n        case -1:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND);\n            return 0;\n\n        case -2:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED);\n            return 0;\n\n        case -3:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND);\n            return 0;\n\n        case -4:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING);\n            return 0;\n\n        case -5:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH);\n            return 0;\n\n        case -6:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_SENDQ);\n            return 0;\n\n        case -7:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION);\n            return 0;\n    }\n\n    /* can't happen */\n    return 0;\n}\n\nvoid tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    callback_file_reqchunk(m, function, user_data);\n}\n\nvoid tox_callback_file_recv(Tox *tox, tox_file_recv_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    callback_file_sendrequest(m, function, user_data);\n}\n\nvoid tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    callback_file_data(m, function, user_data);\n}\n\nstatic void set_custom_packet_error(int ret, TOX_ERR_FRIEND_CUSTOM_PACKET *error)\n{\n    switch (ret) {\n        case 0:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_OK);\n            break;\n\n        case -1:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND);\n            break;\n\n        case -2:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG);\n            break;\n\n        case -3:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID);\n            break;\n\n        case -4:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED);\n            break;\n\n        case -5:\n            SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ);\n            break;\n    }\n}\n\nbool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,\n                                  TOX_ERR_FRIEND_CUSTOM_PACKET *error)\n{\n    if (!data) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL);\n        return 0;\n    }\n\n    Messenger *m = tox;\n\n    if (length == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY);\n        return 0;\n    }\n\n    if (data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID);\n        return 0;\n    }\n\n    int ret = send_custom_lossy_packet(m, friend_number, data, length);\n\n    set_custom_packet_error(ret, error);\n\n    if (ret == 0) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\nvoid tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    custom_lossy_packet_registerhandler(m, function, user_data);\n}\n\nbool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,\n                                     TOX_ERR_FRIEND_CUSTOM_PACKET *error)\n{\n    if (!data) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL);\n        return 0;\n    }\n\n    Messenger *m = tox;\n\n    if (length == 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY);\n        return 0;\n    }\n\n    int ret = send_custom_lossless_packet(m, friend_number, data, length);\n\n    set_custom_packet_error(ret, error);\n\n    if (ret == 0) {\n        return 1;\n    } else {\n        return 0;\n    }\n}\n\nvoid tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *function, void *user_data)\n{\n    Messenger *m = tox;\n    custom_lossless_packet_registerhandler(m, function, user_data);\n}\n\nvoid tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id)\n{\n    if (dht_id) {\n        const Messenger *m = tox;\n        memcpy(dht_id , m->dht->self_public_key, crypto_box_PUBLICKEYBYTES);\n    }\n}\n\nuint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error)\n{\n    const Messenger *m = tox;\n    uint16_t port = htons(m->net->port);\n\n    if (port) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);\n    }\n\n    return port;\n}\n\nuint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error)\n{\n    const Messenger *m = tox;\n\n    if (m->tcp_server) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK);\n        return m->options.tcp_server_port;\n    } else {\n        SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND);\n        return 0;\n    }\n}\n\n#include \"tox_old_code.h\"\n"
  },
  {
    "path": "toxcore/tox.h",
    "content": "/* tox.h\n *\n * The Tox public API.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TOX_H\n#define TOX_H\n\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/*******************************************************************************\n * `tox.h` SHOULD *NOT* BE EDITED MANUALLY – any changes should be made to   *\n * `tox.in.h`, located in `other/apidsl/`. For instructions on how to        *\n * generate `tox.h` from `tox.in.h` please refer to `other/apidsl/README.md` *\n ******************************************************************************/\n\n\n\n/** \\page core Public core API for Tox clients.\n *\n * Every function that can fail takes a function-specific error code pointer\n * that can be used to diagnose problems with the Tox state or the function\n * arguments. The error code pointer can be NULL, which does not influence the\n * function's behaviour, but can be done if the reason for failure is irrelevant\n * to the client.\n *\n * The exception to this rule are simple allocation functions whose only failure\n * mode is allocation failure. They return NULL in that case, and do not set an\n * error code.\n *\n * Every error code type has an OK value to which functions will set their error\n * code value on success. Clients can keep their error code uninitialised before\n * passing it to a function. The library guarantees that after returning, the\n * value pointed to by the error code pointer has been initialised.\n *\n * Functions with pointer parameters often have a NULL error code, meaning they\n * could not perform any operation, because one of the required parameters was\n * NULL. Some functions operate correctly or are defined as effectless on NULL.\n *\n * Some functions additionally return a value outside their\n * return type domain, or a bool containing true on success and false on\n * failure.\n *\n * All functions that take a Tox instance pointer will cause undefined behaviour\n * when passed a NULL Tox pointer.\n *\n * All integer values are expected in host byte order.\n *\n * Functions with parameters with enum types cause unspecified behaviour if the\n * enumeration value is outside the valid range of the type. If possible, the\n * function will try to use a sane default, but there will be no error code,\n * and one possible action for the function to take is to have no effect.\n */\n/** \\subsection events Events and callbacks\n *\n * Events are handled by callbacks. One callback can be registered per event.\n * All events have a callback function type named `tox_{event}_cb` and a\n * function to register it named `tox_callback_{event}`. Passing a NULL\n * callback will result in no callback being registered for that event. Only\n * one callback per event can be registered, so if a client needs multiple\n * event listeners, it needs to implement the dispatch functionality itself.\n */\n/** \\subsection threading Threading implications\n *\n * It is possible to run multiple concurrent threads with a Tox instance for\n * each thread. It is also possible to run all Tox instances in the same thread.\n * A common way to run Tox (multiple or single instance) is to have one thread\n * running a simple tox_iterate loop, sleeping for tox_iteration_interval\n * milliseconds on each iteration.\n *\n * If you want to access a single Tox instance from multiple threads, access\n * to the instance must be synchronised. While multiple threads can concurrently\n * access multiple different Tox instances, no more than one API function can\n * operate on a single instance at any given time.\n *\n * Functions that write to variable length byte arrays will always have a size\n * function associated with them. The result of this size function is only valid\n * until another mutating function (one that takes a pointer to non-const Tox)\n * is called. Thus, clients must ensure that no other thread calls a mutating\n * function between the call to the size function and the call to the retrieval\n * function.\n *\n * E.g. to get the current nickname, one would write\n *\n * \\code\n * size_t length = tox_self_get_name_size(tox);\n * uint8_t *name = malloc(length);\n * if (!name) abort();\n * tox_self_get_name(tox, name);\n * \\endcode\n *\n * If any other thread calls tox_self_set_name while this thread is allocating\n * memory, the length may have become invalid, and the call to\n * tox_self_get_name may cause undefined behaviour.\n */\n/**\n * The Tox instance type. All the state associated with a connection is held\n * within the instance. Multiple instances can exist and operate concurrently.\n * The maximum number of Tox instances that can exist on a single network\n * device is limited. Note that this is not just a per-process limit, since the\n * limiting factor is the number of usable ports on a device.\n */\n#ifndef TOX_DEFINED\n#define TOX_DEFINED\ntypedef struct Tox Tox;\n#endif /* TOX_DEFINED */\n\n\n/*******************************************************************************\n *\n * :: API version\n *\n ******************************************************************************/\n\n\n\n/**\n * The major version number. Incremented when the API or ABI changes in an\n * incompatible way.\n */\n#define TOX_VERSION_MAJOR               0u\n\n/**\n * The minor version number. Incremented when functionality is added without\n * breaking the API or ABI. Set to 0 when the major version number is\n * incremented.\n */\n#define TOX_VERSION_MINOR               0u\n\n/**\n * The patch or revision number. Incremented when bugfixes are applied without\n * changing any functionality or API or ABI.\n */\n#define TOX_VERSION_PATCH               0u\n\n/**\n * A macro to check at preprocessing time whether the client code is compatible\n * with the installed version of Tox.\n */\n#define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH)      \\\n  (TOX_VERSION_MAJOR == MAJOR &&                                \\\n   (TOX_VERSION_MINOR > MINOR ||                                \\\n    (TOX_VERSION_MINOR == MINOR &&                              \\\n     TOX_VERSION_PATCH >= PATCH)))\n\n/**\n * A macro to make compilation fail if the client code is not compatible with\n * the installed version of Tox.\n */\n#define TOX_VERSION_REQUIRE(MAJOR, MINOR, PATCH)                \\\n  typedef char tox_required_version[TOX_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1]\n\n/**\n * Return the major version number of the library. Can be used to display the\n * Tox library version or to check whether the client is compatible with the\n * dynamically linked version of Tox.\n */\nuint32_t tox_version_major(void);\n\n/**\n * Return the minor version number of the library.\n */\nuint32_t tox_version_minor(void);\n\n/**\n * Return the patch number of the library.\n */\nuint32_t tox_version_patch(void);\n\n/**\n * Return whether the compiled library version is compatible with the passed\n * version numbers.\n */\nbool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch);\n\n/**\n * A convenience macro to call tox_version_is_compatible with the currently\n * compiling API version.\n */\n#define TOX_VERSION_IS_ABI_COMPATIBLE()                         \\\n  tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH)\n\n\n/*******************************************************************************\n *\n * :: Numeric constants\n *\n ******************************************************************************/\n\n\n\n/**\n * The size of a Tox Public Key in bytes.\n */\n#define TOX_PUBLIC_KEY_SIZE            32\n\n/**\n * The size of a Tox Secret Key in bytes.\n */\n#define TOX_SECRET_KEY_SIZE            32\n\n/**\n * The size of a Tox address in bytes. Tox addresses are in the format\n * [Public Key (TOX_PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)].\n *\n * The checksum is computed over the Public Key and the nospam value. The first\n * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an\n * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam.\n */\n#define TOX_ADDRESS_SIZE               (TOX_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t))\n\n/**\n * Maximum length of a nickname in bytes.\n */\n#define TOX_MAX_NAME_LENGTH            128\n\n/**\n * Maximum length of a status message in bytes.\n */\n#define TOX_MAX_STATUS_MESSAGE_LENGTH  1007\n\n/**\n * Maximum length of a friend request message in bytes.\n */\n#define TOX_MAX_FRIEND_REQUEST_LENGTH  1016\n\n/**\n * Maximum length of a single message after which it should be split.\n */\n#define TOX_MAX_MESSAGE_LENGTH         1372\n\n/**\n * Maximum size of custom packets. TODO: should be LENGTH?\n */\n#define TOX_MAX_CUSTOM_PACKET_SIZE     1373\n\n/**\n * The number of bytes in a hash generated by tox_hash.\n */\n#define TOX_HASH_LENGTH                32\n\n/**\n * The number of bytes in a file id.\n */\n#define TOX_FILE_ID_LENGTH             32\n\n/**\n * Maximum file name length for file transfers.\n */\n#define TOX_MAX_FILENAME_LENGTH        255\n\n\n/*******************************************************************************\n *\n * :: Global enumerations\n *\n ******************************************************************************/\n\n\n\n/**\n * Represents the possible statuses a client can have.\n */\ntypedef enum TOX_USER_STATUS {\n\n    /**\n     * User is online and available.\n     */\n    TOX_USER_STATUS_NONE,\n\n    /**\n     * User is away. Clients can set this e.g. after a user defined\n     * inactivity time.\n     */\n    TOX_USER_STATUS_AWAY,\n\n    /**\n     * User is busy. Signals to other clients that this client does not\n     * currently wish to communicate.\n     */\n    TOX_USER_STATUS_BUSY,\n\n} TOX_USER_STATUS;\n\n\n/**\n * Represents message types for tox_friend_send_message and group chat\n * messages.\n */\ntypedef enum TOX_MESSAGE_TYPE {\n\n    /**\n     * Normal text message. Similar to PRIVMSG on IRC.\n     */\n    TOX_MESSAGE_TYPE_NORMAL,\n\n    /**\n     * A message describing an user action. This is similar to /me (CTCP ACTION)\n     * on IRC.\n     */\n    TOX_MESSAGE_TYPE_ACTION,\n\n} TOX_MESSAGE_TYPE;\n\n\n\n/*******************************************************************************\n *\n * :: Startup options\n *\n ******************************************************************************/\n\n\n\n/**\n * Type of proxy used to connect to TCP relays.\n */\ntypedef enum TOX_PROXY_TYPE {\n\n    /**\n     * Don't use a proxy.\n     */\n    TOX_PROXY_TYPE_NONE,\n\n    /**\n     * HTTP proxy using CONNECT.\n     */\n    TOX_PROXY_TYPE_HTTP,\n\n    /**\n     * SOCKS proxy for simple socket pipes.\n     */\n    TOX_PROXY_TYPE_SOCKS5,\n\n} TOX_PROXY_TYPE;\n\n\n/**\n * Type of savedata to create the Tox instance from.\n */\ntypedef enum TOX_SAVEDATA_TYPE {\n\n    /**\n     * No savedata.\n     */\n    TOX_SAVEDATA_TYPE_NONE,\n\n    /**\n     * Savedata is one that was obtained from tox_get_savedata\n     */\n    TOX_SAVEDATA_TYPE_TOX_SAVE,\n\n    /**\n     * Savedata is a secret key of length TOX_SECRET_KEY_SIZE\n     */\n    TOX_SAVEDATA_TYPE_SECRET_KEY,\n\n} TOX_SAVEDATA_TYPE;\n\n\n/**\n * This struct contains all the startup options for Tox. You can either allocate\n * this object yourself, and pass it to tox_options_default, or call\n * tox_options_new to get a new default options object.\n */\nstruct Tox_Options {\n\n    /**\n     * The type of socket to create.\n     *\n     * If this is set to false, an IPv4 socket is created, which subsequently\n     * only allows IPv4 communication.\n     * If it is set to true, an IPv6 socket is created, allowing both IPv4 and\n     * IPv6 communication.\n     */\n    bool ipv6_enabled;\n\n\n    /**\n     * Enable the use of UDP communication when available.\n     *\n     * Setting this to false will force Tox to use TCP only. Communications will\n     * need to be relayed through a TCP relay node, potentially slowing them down.\n     * Disabling UDP support is necessary when using anonymous proxies or Tor.\n     */\n    bool udp_enabled;\n\n\n    /**\n     * Pass communications through a proxy.\n     */\n    TOX_PROXY_TYPE proxy_type;\n\n\n    /**\n     * The IP address or DNS name of the proxy to be used.\n     *\n     * If used, this must be non-NULL and be a valid DNS name. The name must not\n     * exceed 255 characters, and be in a NUL-terminated C string format\n     * (255 chars + 1 NUL byte).\n     *\n     * This member is ignored (it can be NULL) if proxy_type is TOX_PROXY_TYPE_NONE.\n     */\n    const char *proxy_host;\n\n\n    /**\n     * The port to use to connect to the proxy server.\n     *\n     * Ports must be in the range (1, 65535). The value is ignored if\n     * proxy_type is TOX_PROXY_TYPE_NONE.\n     */\n    uint16_t proxy_port;\n\n\n    /**\n     * The start port of the inclusive port range to attempt to use.\n     *\n     * If both start_port and end_port are 0, the default port range will be\n     * used: [33445, 33545].\n     *\n     * If either start_port or end_port is 0 while the other is non-zero, the\n     * non-zero port will be the only port in the range.\n     *\n     * Having start_port > end_port will yield the same behavior as if start_port\n     * and end_port were swapped.\n     */\n    uint16_t start_port;\n\n\n    /**\n     * The end port of the inclusive port range to attempt to use.\n     */\n    uint16_t end_port;\n\n\n    /**\n     * The port to use for the TCP server (relay). If 0, the TCP server is\n     * disabled.\n     *\n     * Enabling it is not required for Tox to function properly.\n     *\n     * When enabled, your Tox instance can act as a TCP relay for other Tox\n     * instance. This leads to increased traffic, thus when writing a client\n     * it is recommended to enable TCP server only if the user has an option\n     * to disable it.\n     */\n    uint16_t tcp_port;\n\n\n    /**\n     * The type of savedata to load from.\n     */\n    TOX_SAVEDATA_TYPE savedata_type;\n\n\n    /**\n     * The savedata.\n     */\n    const uint8_t *savedata_data;\n\n\n    /**\n     * The length of the savedata.\n     */\n    size_t savedata_length;\n\n};\n\n\n/**\n * Initialises a Tox_Options object with the default options.\n *\n * The result of this function is independent of the original options. All\n * values will be overwritten, no values will be read (so it is permissible\n * to pass an uninitialised object).\n *\n * If options is NULL, this function has no effect.\n *\n * @param options An options object to be filled with default options.\n */\nvoid tox_options_default(struct Tox_Options *options);\n\ntypedef enum TOX_ERR_OPTIONS_NEW {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_OPTIONS_NEW_OK,\n\n    /**\n     * The function failed to allocate enough memory for the options struct.\n     */\n    TOX_ERR_OPTIONS_NEW_MALLOC,\n\n} TOX_ERR_OPTIONS_NEW;\n\n\n/**\n * Allocates a new Tox_Options object and initialises it with the default\n * options. This function can be used to preserve long term ABI compatibility by\n * giving the responsibility of allocation and deallocation to the Tox library.\n *\n * Objects returned from this function must be freed using the tox_options_free\n * function.\n *\n * @return A new Tox_Options object with default options or NULL on failure.\n */\nstruct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error);\n\n/**\n * Releases all resources associated with an options objects.\n *\n * Passing a pointer that was not returned by tox_options_new results in\n * undefined behaviour.\n */\nvoid tox_options_free(struct Tox_Options *options);\n\n\n/*******************************************************************************\n *\n * :: Creation and destruction\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_NEW {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_NEW_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_NEW_NULL,\n\n    /**\n     * The function was unable to allocate enough memory to store the internal\n     * structures for the Tox object.\n     */\n    TOX_ERR_NEW_MALLOC,\n\n    /**\n     * The function was unable to bind to a port. This may mean that all ports\n     * have already been bound, e.g. by other Tox instances, or it may mean\n     * a permission error. You may be able to gather more information from errno.\n     */\n    TOX_ERR_NEW_PORT_ALLOC,\n\n    /**\n     * proxy_type was invalid.\n     */\n    TOX_ERR_NEW_PROXY_BAD_TYPE,\n\n    /**\n     * proxy_type was valid but the proxy_host passed had an invalid format\n     * or was NULL.\n     */\n    TOX_ERR_NEW_PROXY_BAD_HOST,\n\n    /**\n     * proxy_type was valid, but the proxy_port was invalid.\n     */\n    TOX_ERR_NEW_PROXY_BAD_PORT,\n\n    /**\n     * The proxy address passed could not be resolved.\n     */\n    TOX_ERR_NEW_PROXY_NOT_FOUND,\n\n    /**\n     * The byte array to be loaded contained an encrypted save.\n     */\n    TOX_ERR_NEW_LOAD_ENCRYPTED,\n\n    /**\n     * The data format was invalid. This can happen when loading data that was\n     * saved by an older version of Tox, or when the data has been corrupted.\n     * When loading from badly formatted data, some data may have been loaded,\n     * and the rest is discarded. Passing an invalid length parameter also\n     * causes this error.\n     */\n    TOX_ERR_NEW_LOAD_BAD_FORMAT,\n\n} TOX_ERR_NEW;\n\n\n/**\n * @brief Creates and initialises a new Tox instance with the options passed.\n *\n * This function will bring the instance into a valid state. Running the event\n * loop with a new instance will operate correctly.\n *\n * If loading failed or succeeded only partially, the new or partially loaded\n * instance is returned and an error code is set.\n *\n * @param options An options object as described above. If this parameter is\n *   NULL, the default options are used.\n *\n * @see tox_iterate for the event loop.\n *\n * @return A new Tox instance pointer on success or NULL on failure.\n */\nTox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error);\n\n/**\n * Releases all resources associated with the Tox instance and disconnects from\n * the network.\n *\n * After calling this function, the Tox pointer becomes invalid. No other\n * functions can be called, and the pointer value can no longer be read.\n */\nvoid tox_kill(Tox *tox);\n\n/**\n * Calculates the number of bytes required to store the tox instance with\n * tox_get_savedata. This function cannot fail. The result is always greater than 0.\n *\n * @see threading for concurrency implications.\n */\nsize_t tox_get_savedata_size(const Tox *tox);\n\n/**\n * Store all information associated with the tox instance to a byte array.\n *\n * @param data A memory region large enough to store the tox instance data.\n *   Call tox_get_savedata_size to find the number of bytes required. If this parameter\n *   is NULL, this function has no effect.\n */\nvoid tox_get_savedata(const Tox *tox, uint8_t *savedata);\n\n\n/*******************************************************************************\n *\n * :: Connection lifecycle and event loop\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_BOOTSTRAP {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_BOOTSTRAP_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_BOOTSTRAP_NULL,\n\n    /**\n     * The address could not be resolved to an IP address, or the IP address\n     * passed was invalid.\n     */\n    TOX_ERR_BOOTSTRAP_BAD_HOST,\n\n    /**\n     * The port passed was invalid. The valid port range is (1, 65535).\n     */\n    TOX_ERR_BOOTSTRAP_BAD_PORT,\n\n} TOX_ERR_BOOTSTRAP;\n\n\n/**\n * Sends a \"get nodes\" request to the given bootstrap node with IP, port, and\n * public key to setup connections.\n *\n * This function will attempt to connect to the node using UDP. You must use\n * this function even if Tox_Options.udp_enabled was set to false.\n *\n * @param address The hostname or IP address (IPv4 or IPv6) of the node.\n * @param port The port on the host on which the bootstrap Tox instance is\n *   listening.\n * @param public_key The long term public key of the bootstrap node\n *   (TOX_PUBLIC_KEY_SIZE bytes).\n * @return true on success.\n */\nbool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error);\n\n/**\n * Adds additional host:port pair as TCP relay.\n *\n * This function can be used to initiate TCP connections to different ports on\n * the same bootstrap node, or to add TCP relays without using them as\n * bootstrap nodes.\n *\n * @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay.\n * @param port The port on the host on which the TCP relay is listening.\n * @param public_key The long term public key of the TCP relay\n *   (TOX_PUBLIC_KEY_SIZE bytes).\n * @return true on success.\n */\nbool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key,\n                       TOX_ERR_BOOTSTRAP *error);\n\n/**\n * Protocols that can be used to connect to the network or friends.\n */\ntypedef enum TOX_CONNECTION {\n\n    /**\n     * There is no connection. This instance, or the friend the state change is\n     * about, is now offline.\n     */\n    TOX_CONNECTION_NONE,\n\n    /**\n     * A TCP connection has been established. For the own instance, this means it\n     * is connected through a TCP relay, only. For a friend, this means that the\n     * connection to that particular friend goes through a TCP relay.\n     */\n    TOX_CONNECTION_TCP,\n\n    /**\n     * A UDP connection has been established. For the own instance, this means it\n     * is able to send UDP packets to DHT nodes, but may still be connected to\n     * a TCP relay. For a friend, this means that the connection to that\n     * particular friend was built using direct UDP packets.\n     */\n    TOX_CONNECTION_UDP,\n\n} TOX_CONNECTION;\n\n\n/**\n * Return whether we are connected to the DHT. The return value is equal to the\n * last value received through the `self_connection_status` callback.\n */\nTOX_CONNECTION tox_self_get_connection_status(const Tox *tox);\n\n/**\n * @param connection_status Whether we are connected to the DHT.\n */\ntypedef void tox_self_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data);\n\n\n/**\n * Set the callback for the `self_connection_status` event. Pass NULL to unset.\n *\n * This event is triggered whenever there is a change in the DHT connection\n * state. When disconnected, a client may choose to call tox_bootstrap again, to\n * reconnect to the DHT. Note that this state may frequently change for short\n * amounts of time. Clients should therefore not immediately bootstrap on\n * receiving a disconnect.\n *\n * TODO: how long should a client wait before bootstrapping again?\n */\nvoid tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback, void *user_data);\n\n/**\n * Return the time in milliseconds before tox_iterate() should be called again\n * for optimal performance.\n */\nuint32_t tox_iteration_interval(const Tox *tox);\n\n/**\n * The main loop that needs to be run in intervals of tox_iteration_interval()\n * milliseconds.\n */\nvoid tox_iterate(Tox *tox);\n\n\n/*******************************************************************************\n *\n * :: Internal client information (Tox address/id)\n *\n ******************************************************************************/\n\n\n\n/**\n * Writes the Tox friend address of the client to a byte array. The address is\n * not in human-readable format. If a client wants to display the address,\n * formatting is required.\n *\n * @param address A memory region of at least TOX_ADDRESS_SIZE bytes. If this\n *   parameter is NULL, this function has no effect.\n * @see TOX_ADDRESS_SIZE for the address format.\n */\nvoid tox_self_get_address(const Tox *tox, uint8_t *address);\n\n/**\n * Set the 4-byte nospam part of the address.\n *\n * @param nospam Any 32 bit unsigned integer.\n */\nvoid tox_self_set_nospam(Tox *tox, uint32_t nospam);\n\n/**\n * Get the 4-byte nospam part of the address.\n */\nuint32_t tox_self_get_nospam(const Tox *tox);\n\n/**\n * Copy the Tox Public Key (long term) from the Tox object.\n *\n * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If\n *   this parameter is NULL, this function has no effect.\n */\nvoid tox_self_get_public_key(const Tox *tox, uint8_t *public_key);\n\n/**\n * Copy the Tox Secret Key from the Tox object.\n *\n * @param secret_key A memory region of at least TOX_SECRET_KEY_SIZE bytes. If\n *   this parameter is NULL, this function has no effect.\n */\nvoid tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key);\n\n\n/*******************************************************************************\n *\n * :: User-visible client information (nickname/status)\n *\n ******************************************************************************/\n\n\n\n/**\n * Common error codes for all functions that set a piece of user-visible\n * client information.\n */\ntypedef enum TOX_ERR_SET_INFO {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_SET_INFO_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_SET_INFO_NULL,\n\n    /**\n     * Information length exceeded maximum permissible size.\n     */\n    TOX_ERR_SET_INFO_TOO_LONG,\n\n} TOX_ERR_SET_INFO;\n\n\n/**\n * Set the nickname for the Tox client.\n *\n * Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is 0, the name\n * parameter is ignored (it can be NULL), and the nickname is set back to empty.\n *\n * @param name A byte array containing the new nickname.\n * @param length The size of the name byte array.\n *\n * @return true on success.\n */\nbool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error);\n\n/**\n * Return the length of the current nickname as passed to tox_self_set_name.\n *\n * If no nickname was set before calling this function, the name is empty,\n * and this function returns 0.\n *\n * @see threading for concurrency implications.\n */\nsize_t tox_self_get_name_size(const Tox *tox);\n\n/**\n * Write the nickname set by tox_self_set_name to a byte array.\n *\n * If no nickname was set before calling this function, the name is empty,\n * and this function has no effect.\n *\n * Call tox_self_get_name_size to find out how much memory to allocate for\n * the result.\n *\n * @param name A valid memory location large enough to hold the nickname.\n *   If this parameter is NULL, the function has no effect.\n */\nvoid tox_self_get_name(const Tox *tox, uint8_t *name);\n\n/**\n * Set the client's status message.\n *\n * Status message length cannot exceed TOX_MAX_STATUS_MESSAGE_LENGTH. If\n * length is 0, the status parameter is ignored (it can be NULL), and the\n * user status is set back to empty.\n */\nbool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, TOX_ERR_SET_INFO *error);\n\n/**\n * Return the length of the current status message as passed to tox_self_set_status_message.\n *\n * If no status message was set before calling this function, the status\n * is empty, and this function returns 0.\n *\n * @see threading for concurrency implications.\n */\nsize_t tox_self_get_status_message_size(const Tox *tox);\n\n/**\n * Write the status message set by tox_self_set_status_message to a byte array.\n *\n * If no status message was set before calling this function, the status is\n * empty, and this function has no effect.\n *\n * Call tox_self_get_status_message_size to find out how much memory to allocate for\n * the result.\n *\n * @param status A valid memory location large enough to hold the status message.\n *   If this parameter is NULL, the function has no effect.\n */\nvoid tox_self_get_status_message(const Tox *tox, uint8_t *status_message);\n\n/**\n * Set the client's user status.\n *\n * @param user_status One of the user statuses listed in the enumeration above.\n */\nvoid tox_self_set_status(Tox *tox, TOX_USER_STATUS status);\n\n/**\n * Returns the client's user status.\n */\nTOX_USER_STATUS tox_self_get_status(const Tox *tox);\n\n\n/*******************************************************************************\n *\n * :: Friend list management\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_FRIEND_ADD {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_ADD_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_FRIEND_ADD_NULL,\n\n    /**\n     * The length of the friend request message exceeded\n     * TOX_MAX_FRIEND_REQUEST_LENGTH.\n     */\n    TOX_ERR_FRIEND_ADD_TOO_LONG,\n\n    /**\n     * The friend request message was empty. This, and the TOO_LONG code will\n     * never be returned from tox_friend_add_norequest.\n     */\n    TOX_ERR_FRIEND_ADD_NO_MESSAGE,\n\n    /**\n     * The friend address belongs to the sending client.\n     */\n    TOX_ERR_FRIEND_ADD_OWN_KEY,\n\n    /**\n     * A friend request has already been sent, or the address belongs to a friend\n     * that is already on the friend list.\n     */\n    TOX_ERR_FRIEND_ADD_ALREADY_SENT,\n\n    /**\n     * The friend address checksum failed.\n     */\n    TOX_ERR_FRIEND_ADD_BAD_CHECKSUM,\n\n    /**\n     * The friend was already there, but the nospam value was different.\n     */\n    TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM,\n\n    /**\n     * A memory allocation failed when trying to increase the friend list size.\n     */\n    TOX_ERR_FRIEND_ADD_MALLOC,\n\n} TOX_ERR_FRIEND_ADD;\n\n\n/**\n * Add a friend to the friend list and send a friend request.\n *\n * A friend request message must be at least 1 byte long and at most\n * TOX_MAX_FRIEND_REQUEST_LENGTH.\n *\n * Friend numbers are unique identifiers used in all functions that operate on\n * friends. Once added, a friend number is stable for the lifetime of the Tox\n * object. After saving the state and reloading it, the friend numbers may not\n * be the same as before. Deleting a friend creates a gap in the friend number\n * set, which is filled by the next adding of a friend. Any pattern in friend\n * numbers should not be relied on.\n *\n * If more than INT32_MAX friends are added, this function causes undefined\n * behaviour.\n *\n * @param address The address of the friend (returned by tox_self_get_address of\n *   the friend you wish to add) it must be TOX_ADDRESS_SIZE bytes.\n * @param message The message that will be sent along with the friend request.\n * @param length The length of the data byte array.\n *\n * @return the friend number on success, UINT32_MAX on failure.\n */\nuint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length,\n                        TOX_ERR_FRIEND_ADD *error);\n\n/**\n * Add a friend without sending a friend request.\n *\n * This function is used to add a friend in response to a friend request. If the\n * client receives a friend request, it can be reasonably sure that the other\n * client added this client as a friend, eliminating the need for a friend\n * request.\n *\n * This function is also useful in a situation where both instances are\n * controlled by the same entity, so that this entity can perform the mutual\n * friend adding. In this case, there is no need for a friend request, either.\n *\n * @param public_key A byte array of length TOX_PUBLIC_KEY_SIZE containing the\n *   Public Key (not the Address) of the friend to add.\n *\n * @return the friend number on success, UINT32_MAX on failure.\n * @see tox_friend_add for a more detailed description of friend numbers.\n */\nuint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error);\n\ntypedef enum TOX_ERR_FRIEND_DELETE {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_DELETE_OK,\n\n    /**\n     * There was no friend with the given friend number. No friends were deleted.\n     */\n    TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND,\n\n} TOX_ERR_FRIEND_DELETE;\n\n\n/**\n * Remove a friend from the friend list.\n *\n * This does not notify the friend of their deletion. After calling this\n * function, this client will appear offline to the friend and no communication\n * can occur between the two.\n *\n * @param friend_number Friend number for the friend to be deleted.\n *\n * @return true on success.\n */\nbool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error);\n\n\n/*******************************************************************************\n *\n * :: Friend list queries\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_FRIEND_BY_PUBLIC_KEY {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL,\n\n    /**\n     * No friend with the given Public Key exists on the friend list.\n     */\n    TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND,\n\n} TOX_ERR_FRIEND_BY_PUBLIC_KEY;\n\n\n/**\n * Return the friend number associated with that Public Key.\n *\n * @return the friend number on success, UINT32_MAX on failure.\n * @param public_key A byte array containing the Public Key.\n */\nuint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error);\n\n/**\n * Checks if a friend with the given friend number exists and returns true if\n * it does.\n */\nbool tox_friend_exists(const Tox *tox, uint32_t friend_number);\n\n/**\n * Return the number of friends on the friend list.\n *\n * This function can be used to determine how much memory to allocate for\n * tox_self_get_friend_list.\n */\nsize_t tox_self_get_friend_list_size(const Tox *tox);\n\n/**\n * Copy a list of valid friend numbers into an array.\n *\n * Call tox_self_get_friend_list_size to determine the number of elements to allocate.\n *\n * @param list A memory region with enough space to hold the friend list. If\n *   this parameter is NULL, this function has no effect.\n */\nvoid tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list);\n\ntypedef enum TOX_ERR_FRIEND_GET_PUBLIC_KEY {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK,\n\n    /**\n     * No friend with the given number exists on the friend list.\n     */\n    TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND,\n\n} TOX_ERR_FRIEND_GET_PUBLIC_KEY;\n\n\n/**\n * Copies the Public Key associated with a given friend number to a byte array.\n *\n * @param friend_number The friend number you want the Public Key of.\n * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If\n *   this parameter is NULL, this function has no effect.\n *\n * @return true on success.\n */\nbool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key,\n                               TOX_ERR_FRIEND_GET_PUBLIC_KEY *error);\n\ntypedef enum TOX_ERR_FRIEND_GET_LAST_ONLINE {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_GET_LAST_ONLINE_OK,\n\n    /**\n     * No friend with the given number exists on the friend list.\n     */\n    TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND,\n\n} TOX_ERR_FRIEND_GET_LAST_ONLINE;\n\n\n/**\n * Return a unix-time timestamp of the last time the friend associated with a given\n * friend number was seen online. This function will return UINT64_MAX on error.\n *\n * @param friend_number The friend number you want to query.\n */\nuint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error);\n\n\n/*******************************************************************************\n *\n * :: Friend-specific state queries (can also be received through callbacks)\n *\n ******************************************************************************/\n\n\n\n/**\n * Common error codes for friend state query functions.\n */\ntypedef enum TOX_ERR_FRIEND_QUERY {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_QUERY_OK,\n\n    /**\n     * The pointer parameter for storing the query result (name, message) was\n     * NULL. Unlike the `_self_` variants of these functions, which have no effect\n     * when a parameter is NULL, these functions return an error in that case.\n     */\n    TOX_ERR_FRIEND_QUERY_NULL,\n\n    /**\n     * The friend_number did not designate a valid friend.\n     */\n    TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND,\n\n} TOX_ERR_FRIEND_QUERY;\n\n\n/**\n * Return the length of the friend's name. If the friend number is invalid, the\n * return value is unspecified.\n *\n * The return value is equal to the `length` argument received by the last\n * `friend_name` callback.\n */\nsize_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * Write the name of the friend designated by the given friend number to a byte\n * array.\n *\n * Call tox_friend_get_name_size to determine the allocation size for the `name`\n * parameter.\n *\n * The data written to `name` is equal to the data received by the last\n * `friend_name` callback.\n *\n * @param name A valid memory region large enough to store the friend's name.\n *\n * @return true on success.\n */\nbool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * @param friend_number The friend number of the friend whose name changed.\n * @param name A byte array containing the same data as\n *   tox_friend_get_name would write to its `name` parameter.\n * @param length A value equal to the return value of\n *   tox_friend_get_name_size.\n */\ntypedef void tox_friend_name_cb(Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length, void *user_data);\n\n\n/**\n * Set the callback for the `friend_name` event. Pass NULL to unset.\n *\n * This event is triggered when a friend changes their name.\n */\nvoid tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback, void *user_data);\n\n/**\n * Return the length of the friend's status message. If the friend number is\n * invalid, the return value is SIZE_MAX.\n */\nsize_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * Write the status message of the friend designated by the given friend number to a byte\n * array.\n *\n * Call tox_friend_get_status_message_size to determine the allocation size for the `status_name`\n * parameter.\n *\n * The data written to `status_message` is equal to the data received by the last\n * `friend_status_message` callback.\n *\n * @param status_message A valid memory region large enough to store the friend's status message.\n */\nbool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message,\n                                   TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * @param friend_number The friend number of the friend whose status message\n *   changed.\n * @param message A byte array containing the same data as\n *   tox_friend_get_status_message would write to its `status_message` parameter.\n * @param length A value equal to the return value of\n *   tox_friend_get_status_message_size.\n */\ntypedef void tox_friend_status_message_cb(Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length,\n        void *user_data);\n\n\n/**\n * Set the callback for the `friend_status_message` event. Pass NULL to unset.\n *\n * This event is triggered when a friend changes their status message.\n */\nvoid tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback, void *user_data);\n\n/**\n * Return the friend's user status (away/busy/...). If the friend number is\n * invalid, the return value is unspecified.\n *\n * The status returned is equal to the last status received through the\n * `friend_status` callback.\n */\nTOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * @param friend_number The friend number of the friend whose user status\n *   changed.\n * @param status The new user status.\n */\ntypedef void tox_friend_status_cb(Tox *tox, uint32_t friend_number, TOX_USER_STATUS status, void *user_data);\n\n\n/**\n * Set the callback for the `friend_status` event. Pass NULL to unset.\n *\n * This event is triggered when a friend changes their user status.\n */\nvoid tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback, void *user_data);\n\n/**\n * Check whether a friend is currently connected to this client.\n *\n * The result of this function is equal to the last value received by the\n * `friend_connection_status` callback.\n *\n * @param friend_number The friend number for which to query the connection\n *   status.\n *\n * @return the friend's connection status as it was received through the\n *   `friend_connection_status` event.\n */\nTOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * @param friend_number The friend number of the friend whose connection status\n *   changed.\n * @param connection_status The result of calling\n *   tox_friend_get_connection_status on the passed friend_number.\n */\ntypedef void tox_friend_connection_status_cb(Tox *tox, uint32_t friend_number, TOX_CONNECTION connection_status,\n        void *user_data);\n\n\n/**\n * Set the callback for the `friend_connection_status` event. Pass NULL to unset.\n *\n * This event is triggered when a friend goes offline after having been online,\n * or when a friend goes online.\n *\n * This callback is not called when adding friends. It is assumed that when\n * adding friends, their connection status is initially offline.\n */\nvoid tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback, void *user_data);\n\n/**\n * Check whether a friend is currently typing a message.\n *\n * @param friend_number The friend number for which to query the typing status.\n *\n * @return true if the friend is typing.\n * @return false if the friend is not typing, or the friend number was\n *   invalid. Inspect the error code to determine which case it is.\n */\nbool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error);\n\n/**\n * @param friend_number The friend number of the friend who started or stopped\n *   typing.\n * @param is_typing The result of calling tox_friend_get_typing on the passed\n *   friend_number.\n */\ntypedef void tox_friend_typing_cb(Tox *tox, uint32_t friend_number, bool is_typing, void *user_data);\n\n\n/**\n * Set the callback for the `friend_typing` event. Pass NULL to unset.\n *\n * This event is triggered when a friend starts or stops typing.\n */\nvoid tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: Sending private messages\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_SET_TYPING {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_SET_TYPING_OK,\n\n    /**\n     * The friend number did not designate a valid friend.\n     */\n    TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND,\n\n} TOX_ERR_SET_TYPING;\n\n\n/**\n * Set the client's typing status for a friend.\n *\n * The client is responsible for turning it on or off.\n *\n * @param friend_number The friend to which the client is typing a message.\n * @param typing The typing status. True means the client is typing.\n *\n * @return true on success.\n */\nbool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, TOX_ERR_SET_TYPING *error);\n\ntypedef enum TOX_ERR_FRIEND_SEND_MESSAGE {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_NULL,\n\n    /**\n     * The friend number did not designate a valid friend.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not connected to the friend.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED,\n\n    /**\n     * An allocation error occurred while increasing the send queue size.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ,\n\n    /**\n     * Message length exceeded TOX_MAX_MESSAGE_LENGTH.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG,\n\n    /**\n     * Attempted to send a zero-length message.\n     */\n    TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY,\n\n} TOX_ERR_FRIEND_SEND_MESSAGE;\n\n\n/**\n * Send a text chat message to an online friend.\n *\n * This function creates a chat message packet and pushes it into the send\n * queue.\n *\n * The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages\n * must be split by the client and sent as separate messages. Other clients can\n * then reassemble the fragments. Messages may not be empty.\n *\n * The return value of this function is the message ID. If a read receipt is\n * received, the triggered `friend_read_receipt` event will be passed this message ID.\n *\n * Message IDs are unique per friend. The first message ID is 0. Message IDs are\n * incremented by 1 each time a message is sent. If UINT32_MAX messages were\n * sent, the next message ID is 0.\n *\n * @param type Message type (normal, action, ...).\n * @param friend_number The friend number of the friend to send the message to.\n * @param message A non-NULL pointer to the first element of a byte array\n *   containing the message text.\n * @param length Length of the message to be sent.\n */\nuint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message,\n                                 size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error);\n\n/**\n * @param friend_number The friend number of the friend who received the message.\n * @param message_id The message ID as returned from tox_friend_send_message\n *   corresponding to the message sent.\n */\ntypedef void tox_friend_read_receipt_cb(Tox *tox, uint32_t friend_number, uint32_t message_id, void *user_data);\n\n\n/**\n * Set the callback for the `friend_read_receipt` event. Pass NULL to unset.\n *\n * This event is triggered when the friend receives the message sent with\n * tox_friend_send_message with the corresponding message ID.\n */\nvoid tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: Receiving private messages and friend requests\n *\n ******************************************************************************/\n\n\n\n/**\n * @param public_key The Public Key of the user who sent the friend request.\n * @param time_delta A delta in seconds between when the message was composed\n *   and when it is being transmitted. For messages that are sent immediately,\n *   it will be 0. If a message was written and couldn't be sent immediately\n *   (due to a connection failure, for example), the time_delta is an\n *   approximation of when it was composed.\n * @param message The message they sent along with the request.\n * @param length The size of the message byte array.\n */\ntypedef void tox_friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length,\n                                   void *user_data);\n\n\n/**\n * Set the callback for the `friend_request` event. Pass NULL to unset.\n *\n * This event is triggered when a friend request is received.\n */\nvoid tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback, void *user_data);\n\n/**\n * @param friend_number The friend number of the friend who sent the message.\n * @param time_delta Time between composition and sending.\n * @param message The message data they sent.\n * @param length The size of the message byte array.\n *\n * @see friend_request for more information on time_delta.\n */\ntypedef void tox_friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message,\n                                   size_t length, void *user_data);\n\n\n/**\n * Set the callback for the `friend_message` event. Pass NULL to unset.\n *\n * This event is triggered when a message from a friend is received.\n */\nvoid tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: File transmission: common between sending and receiving\n *\n ******************************************************************************/\n\n\n\n/**\n * Generates a cryptographic hash of the given data.\n *\n * This function may be used by clients for any purpose, but is provided\n * primarily for validating cached avatars. This use is highly recommended to\n * avoid unnecessary avatar updates.\n *\n * If hash is NULL or data is NULL while length is not 0 the function returns false,\n * otherwise it returns true.\n *\n * This function is a wrapper to internal message-digest functions.\n *\n * @param hash A valid memory location the hash data. It must be at least\n *   TOX_HASH_LENGTH bytes in size.\n * @param data Data to be hashed or NULL.\n * @param length Size of the data array or 0.\n *\n * @return true if hash was not NULL.\n */\nbool tox_hash(uint8_t *hash, const uint8_t *data, size_t length);\n\nenum TOX_FILE_KIND {\n\n    /**\n     * Arbitrary file data. Clients can choose to handle it based on the file name\n     * or magic or any other way they choose.\n     */\n    TOX_FILE_KIND_DATA,\n\n    /**\n     * Avatar file_id. This consists of tox_hash(image).\n     * Avatar data. This consists of the image data.\n     *\n     * Avatars can be sent at any time the client wishes. Generally, a client will\n     * send the avatar to a friend when that friend comes online, and to all\n     * friends when the avatar changed. A client can save some traffic by\n     * remembering which friend received the updated avatar already and only send\n     * it if the friend has an out of date avatar.\n     *\n     * Clients who receive avatar send requests can reject it (by sending\n     * TOX_FILE_CONTROL_CANCEL before any other controls), or accept it (by\n     * sending TOX_FILE_CONTROL_RESUME). The file_id of length TOX_HASH_LENGTH bytes\n     * (same length as TOX_FILE_ID_LENGTH) will contain the hash. A client can compare\n     * this hash with a saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar\n     * transfer if it matches.\n     *\n     * When file_size is set to 0 in the transfer request it means that the client\n     * has no avatar.\n     */\n    TOX_FILE_KIND_AVATAR,\n\n};\n\n\ntypedef enum TOX_FILE_CONTROL {\n\n    /**\n     * Sent by the receiving side to accept a file send request. Also sent after a\n     * TOX_FILE_CONTROL_PAUSE command to continue sending or receiving.\n     */\n    TOX_FILE_CONTROL_RESUME,\n\n    /**\n     * Sent by clients to pause the file transfer. The initial state of a file\n     * transfer is always paused on the receiving side and running on the sending\n     * side. If both the sending and receiving side pause the transfer, then both\n     * need to send TOX_FILE_CONTROL_RESUME for the transfer to resume.\n     */\n    TOX_FILE_CONTROL_PAUSE,\n\n    /**\n     * Sent by the receiving side to reject a file send request before any other\n     * commands are sent. Also sent by either side to terminate a file transfer.\n     */\n    TOX_FILE_CONTROL_CANCEL,\n\n} TOX_FILE_CONTROL;\n\n\ntypedef enum TOX_ERR_FILE_CONTROL {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FILE_CONTROL_OK,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not connected to the friend.\n     */\n    TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED,\n\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    TOX_ERR_FILE_CONTROL_NOT_FOUND,\n\n    /**\n     * A RESUME control was sent, but the file transfer is running normally.\n     */\n    TOX_ERR_FILE_CONTROL_NOT_PAUSED,\n\n    /**\n     * A RESUME control was sent, but the file transfer was paused by the other\n     * party. Only the party that paused the transfer can resume it.\n     */\n    TOX_ERR_FILE_CONTROL_DENIED,\n\n    /**\n     * A PAUSE control was sent, but the file transfer was already paused.\n     */\n    TOX_ERR_FILE_CONTROL_ALREADY_PAUSED,\n\n    /**\n     * Packet queue is full.\n     */\n    TOX_ERR_FILE_CONTROL_SENDQ,\n\n} TOX_ERR_FILE_CONTROL;\n\n\n/**\n * Sends a file control command to a friend for a given file transfer.\n *\n * @param friend_number The friend number of the friend the file is being\n *   transferred to or received from.\n * @param file_number The friend-specific identifier for the file transfer.\n * @param control The control command to send.\n *\n * @return true on success.\n */\nbool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,\n                      TOX_ERR_FILE_CONTROL *error);\n\n/**\n * When receiving TOX_FILE_CONTROL_CANCEL, the client should release the\n * resources associated with the file number and consider the transfer failed.\n *\n * @param friend_number The friend number of the friend who is sending the file.\n * @param file_number The friend-specific file number the data received is\n *   associated with.\n * @param control The file control command received.\n */\ntypedef void tox_file_recv_control_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control,\n                                      void *user_data);\n\n\n/**\n * Set the callback for the `file_recv_control` event. Pass NULL to unset.\n *\n * This event is triggered when a file control command is received from a\n * friend.\n */\nvoid tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback, void *user_data);\n\ntypedef enum TOX_ERR_FILE_SEEK {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FILE_SEEK_OK,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not connected to the friend.\n     */\n    TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED,\n\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    TOX_ERR_FILE_SEEK_NOT_FOUND,\n\n    /**\n     * File was not in a state where it could be seeked.\n     */\n    TOX_ERR_FILE_SEEK_DENIED,\n\n    /**\n     * Seek position was invalid\n     */\n    TOX_ERR_FILE_SEEK_INVALID_POSITION,\n\n    /**\n     * Packet queue is full.\n     */\n    TOX_ERR_FILE_SEEK_SENDQ,\n\n} TOX_ERR_FILE_SEEK;\n\n\n/**\n * Sends a file seek control command to a friend for a given file transfer.\n *\n * This function can only be called to resume a file transfer right before\n * TOX_FILE_CONTROL_RESUME is sent.\n *\n * @param friend_number The friend number of the friend the file is being\n *   received from.\n * @param file_number The friend-specific identifier for the file transfer.\n * @param position The position that the file should be seeked to.\n */\nbool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, TOX_ERR_FILE_SEEK *error);\n\ntypedef enum TOX_ERR_FILE_GET {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FILE_GET_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_FILE_GET_NULL,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOX_ERR_FILE_GET_FRIEND_NOT_FOUND,\n\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    TOX_ERR_FILE_GET_NOT_FOUND,\n\n} TOX_ERR_FILE_GET;\n\n\n/**\n * Copy the file id associated to the file transfer to a byte array.\n *\n * @param friend_number The friend number of the friend the file is being\n *   transferred to or received from.\n * @param file_number The friend-specific identifier for the file transfer.\n * @param file_id A memory region of at least TOX_FILE_ID_LENGTH bytes. If\n *   this parameter is NULL, this function has no effect.\n *\n * @return true on success.\n */\nbool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id,\n                          TOX_ERR_FILE_GET *error);\n\n\n/*******************************************************************************\n *\n * :: File transmission: sending\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_FILE_SEND {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FILE_SEND_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_FILE_SEND_NULL,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not connected to the friend.\n     */\n    TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED,\n\n    /**\n     * Filename length exceeded TOX_MAX_FILENAME_LENGTH bytes.\n     */\n    TOX_ERR_FILE_SEND_NAME_TOO_LONG,\n\n    /**\n     * Too many ongoing transfers. The maximum number of concurrent file transfers\n     * is 256 per friend per direction (sending and receiving).\n     */\n    TOX_ERR_FILE_SEND_TOO_MANY,\n\n} TOX_ERR_FILE_SEND;\n\n\n/**\n * Send a file transmission request.\n *\n * Maximum filename length is TOX_MAX_FILENAME_LENGTH bytes. The filename\n * should generally just be a file name, not a path with directory names.\n *\n * If a non-UINT64_MAX file size is provided, it can be used by both sides to\n * determine the sending progress. File size can be set to UINT64_MAX for streaming\n * data of unknown size.\n *\n * File transmission occurs in chunks, which are requested through the\n * `file_chunk_request` event.\n *\n * When a friend goes offline, all file transfers associated with the friend are\n * purged from core.\n *\n * If the file contents change during a transfer, the behaviour is unspecified\n * in general. What will actually happen depends on the mode in which the file\n * was modified and how the client determines the file size.\n *\n * - If the file size was increased\n *   - and sending mode was streaming (file_size = UINT64_MAX), the behaviour\n *     will be as expected.\n *   - and sending mode was file (file_size != UINT64_MAX), the\n *     file_chunk_request callback will receive length = 0 when Core thinks\n *     the file transfer has finished. If the client remembers the file size as\n *     it was when sending the request, it will terminate the transfer normally.\n *     If the client re-reads the size, it will think the friend cancelled the\n *     transfer.\n * - If the file size was decreased\n *   - and sending mode was streaming, the behaviour is as expected.\n *   - and sending mode was file, the callback will return 0 at the new\n *     (earlier) end-of-file, signalling to the friend that the transfer was\n *     cancelled.\n * - If the file contents were modified\n *   - at a position before the current read, the two files (local and remote)\n *     will differ after the transfer terminates.\n *   - at a position after the current read, the file transfer will succeed as\n *     expected.\n *   - In either case, both sides will regard the transfer as complete and\n *     successful.\n *\n * @param friend_number The friend number of the friend the file send request\n *   should be sent to.\n * @param kind The meaning of the file to be sent.\n * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if\n *   unknown or streaming.\n * @param file_id A file identifier of length TOX_FILE_ID_LENGTH that can be used to\n *   uniquely identify file transfers across core restarts. If NULL, a random one will\n *   be generated by core. It can then be obtained by using tox_file_get_file_id().\n * @param filename Name of the file. Does not need to be the actual name. This\n *   name will be sent along with the file send request.\n * @param filename_length Size in bytes of the filename.\n *\n * @return A file number used as an identifier in subsequent callbacks. This\n *   number is per friend. File numbers are reused after a transfer terminates.\n *   On failure, this function returns UINT32_MAX. Any pattern in file numbers\n *   should not be relied on.\n */\nuint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id,\n                       const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error);\n\ntypedef enum TOX_ERR_FILE_SEND_CHUNK {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_OK,\n\n    /**\n     * The length parameter was non-zero, but data was NULL.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_NULL,\n\n    /**\n     * The friend_number passed did not designate a valid friend.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not connected to the friend.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED,\n\n    /**\n     * No file transfer with the given file number was found for the given friend.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND,\n\n    /**\n     * File transfer was found but isn't in a transferring state: (paused, done,\n     * broken, etc...) (happens only when not called from the request chunk callback).\n     */\n    TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING,\n\n    /**\n     * Attempted to send more or less data than requested. The requested data size is\n     * adjusted according to maximum transmission unit and the expected end of\n     * the file. Trying to send less or more than requested will return this error.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH,\n\n    /**\n     * Packet queue is full.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_SENDQ,\n\n    /**\n     * Position parameter was wrong.\n     */\n    TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION,\n\n} TOX_ERR_FILE_SEND_CHUNK;\n\n\n/**\n * Send a chunk of file data to a friend.\n *\n * This function is called in response to the `file_chunk_request` callback. The\n * length parameter should be equal to the one received though the callback.\n * If it is zero, the transfer is assumed complete. For files with known size,\n * Core will know that the transfer is complete after the last byte has been\n * received, so it is not necessary (though not harmful) to send a zero-length\n * chunk to terminate. For streams, core will know that the transfer is finished\n * if a chunk with length less than the length requested in the callback is sent.\n *\n * @param friend_number The friend number of the receiving friend for this file.\n * @param file_number The file transfer identifier returned by tox_file_send.\n * @param position The file or stream position from which to continue reading.\n * @return true on success.\n */\nbool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data,\n                         size_t length, TOX_ERR_FILE_SEND_CHUNK *error);\n\n/**\n * If the length parameter is 0, the file transfer is finished, and the client's\n * resources associated with the file number should be released. After a call\n * with zero length, the file number can be reused for future file transfers.\n *\n * If the requested position is not equal to the client's idea of the current\n * file or stream position, it will need to seek. In case of read-once streams,\n * the client should keep the last read chunk so that a seek back can be\n * supported. A seek-back only ever needs to read from the last requested chunk.\n * This happens when a chunk was requested, but the send failed. A seek-back\n * request can occur an arbitrary number of times for any given chunk.\n *\n * In response to receiving this callback, the client should call the function\n * `tox_file_send_chunk` with the requested chunk. If the number of bytes sent\n * through that function is zero, the file transfer is assumed complete. A\n * client must send the full length of data requested with this callback.\n *\n * @param friend_number The friend number of the receiving friend for this file.\n * @param file_number The file transfer identifier returned by tox_file_send.\n * @param position The file or stream position from which to continue reading.\n * @param length The number of bytes requested for the current chunk.\n */\ntypedef void tox_file_chunk_request_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,\n                                       size_t length, void *user_data);\n\n\n/**\n * Set the callback for the `file_chunk_request` event. Pass NULL to unset.\n *\n * This event is triggered when Core is ready to send more file data.\n */\nvoid tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: File transmission: receiving\n *\n ******************************************************************************/\n\n\n\n/**\n * The client should acquire resources to be associated with the file transfer.\n * Incoming file transfers start in the PAUSED state. After this callback\n * returns, a transfer can be rejected by sending a TOX_FILE_CONTROL_CANCEL\n * control command before any other control commands. It can be accepted by\n * sending TOX_FILE_CONTROL_RESUME.\n *\n * @param friend_number The friend number of the friend who is sending the file\n *   transfer request.\n * @param file_number The friend-specific file number the data received is\n *   associated with.\n * @param kind The meaning of the file to be sent.\n * @param file_size Size in bytes of the file the client wants to send,\n *   UINT64_MAX if unknown or streaming.\n * @param filename Name of the file. Does not need to be the actual name. This\n *   name will be sent along with the file send request.\n * @param filename_length Size in bytes of the filename.\n */\ntypedef void tox_file_recv_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t file_size,\n                              const uint8_t *filename, size_t filename_length, void *user_data);\n\n\n/**\n * Set the callback for the `file_recv` event. Pass NULL to unset.\n *\n * This event is triggered when a file transfer request is received.\n */\nvoid tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback, void *user_data);\n\n/**\n * When length is 0, the transfer is finished and the client should release the\n * resources it acquired for the transfer. After a call with length = 0, the\n * file number can be reused for new file transfers.\n *\n * If position is equal to file_size (received in the file_receive callback)\n * when the transfer finishes, the file was received completely. Otherwise, if\n * file_size was UINT64_MAX, streaming ended successfully when length is 0.\n *\n * @param friend_number The friend number of the friend who is sending the file.\n * @param file_number The friend-specific file number the data received is\n *   associated with.\n * @param position The file position of the first byte in data.\n * @param data A byte array containing the received chunk.\n * @param length The length of the received chunk.\n */\ntypedef void tox_file_recv_chunk_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position,\n                                    const uint8_t *data, size_t length, void *user_data);\n\n\n/**\n * Set the callback for the `file_recv_chunk` event. Pass NULL to unset.\n *\n * This event is first triggered when a file transfer request is received, and\n * subsequently when a chunk of file data for an accepted request was received.\n */\nvoid tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: Group chat management\n *\n ******************************************************************************/\n\n\n\n\n/*******************************************************************************\n *\n * :: Group chat message sending and receiving\n *\n ******************************************************************************/\n\n\n\n\n/*******************************************************************************\n *\n * :: Low-level custom packet sending and receiving\n *\n ******************************************************************************/\n\n\n\ntypedef enum TOX_ERR_FRIEND_CUSTOM_PACKET {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_OK,\n\n    /**\n     * One of the arguments to the function was NULL when it was not expected.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_NULL,\n\n    /**\n     * The friend number did not designate a valid friend.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND,\n\n    /**\n     * This client is currently not connected to the friend.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED,\n\n    /**\n     * The first byte of data was not in the specified range for the packet type.\n     * This range is 200-254 for lossy, and 160-191 for lossless packets.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID,\n\n    /**\n     * Attempted to send an empty packet.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY,\n\n    /**\n     * Packet data length exceeded TOX_MAX_CUSTOM_PACKET_SIZE.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG,\n\n    /**\n     * Packet queue is full.\n     */\n    TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ,\n\n} TOX_ERR_FRIEND_CUSTOM_PACKET;\n\n\n/**\n * Send a custom lossy packet to a friend.\n *\n * The first byte of data must be in the range 200-254. Maximum length of a\n * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE.\n *\n * Lossy packets behave like UDP packets, meaning they might never reach the\n * other side or might arrive more than once (if someone is messing with the\n * connection) or might arrive in the wrong order.\n *\n * Unless latency is an issue, it is recommended that you use lossless custom\n * packets instead.\n *\n * @param friend_number The friend number of the friend this lossy packet\n *   should be sent to.\n * @param data A byte array containing the packet data.\n * @param length The length of the packet data byte array.\n *\n * @return true on success.\n */\nbool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,\n                                  TOX_ERR_FRIEND_CUSTOM_PACKET *error);\n\n/**\n * Send a custom lossless packet to a friend.\n *\n * The first byte of data must be in the range 160-191. Maximum length of a\n * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE.\n *\n * Lossless packet behaviour is comparable to TCP (reliability, arrive in order)\n * but with packets instead of a stream.\n *\n * @param friend_number The friend number of the friend this lossless packet\n *   should be sent to.\n * @param data A byte array containing the packet data.\n * @param length The length of the packet data byte array.\n *\n * @return true on success.\n */\nbool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,\n                                     TOX_ERR_FRIEND_CUSTOM_PACKET *error);\n\n/**\n * @param friend_number The friend number of the friend who sent a lossy packet.\n * @param data A byte array containing the received packet data.\n * @param length The length of the packet data byte array.\n */\ntypedef void tox_friend_lossy_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,\n                                        void *user_data);\n\n\n/**\n * Set the callback for the `friend_lossy_packet` event. Pass NULL to unset.\n *\n */\nvoid tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback, void *user_data);\n\n/**\n * @param friend_number The friend number of the friend who sent the packet.\n * @param data A byte array containing the received packet data.\n * @param length The length of the packet data byte array.\n */\ntypedef void tox_friend_lossless_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length,\n        void *user_data);\n\n\n/**\n * Set the callback for the `friend_lossless_packet` event. Pass NULL to unset.\n *\n */\nvoid tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback, void *user_data);\n\n\n/*******************************************************************************\n *\n * :: Low-level network information\n *\n ******************************************************************************/\n\n\n\n/**\n * Writes the temporary DHT public key of this instance to a byte array.\n *\n * This can be used in combination with an externally accessible IP address and\n * the bound port (from tox_self_get_udp_port) to run a temporary bootstrap node.\n *\n * Be aware that every time a new instance is created, the DHT public key\n * changes, meaning this cannot be used to run a permanent bootstrap node.\n *\n * @param dht_id A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If this\n *   parameter is NULL, this function has no effect.\n */\nvoid tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id);\n\ntypedef enum TOX_ERR_GET_PORT {\n\n    /**\n     * The function returned successfully.\n     */\n    TOX_ERR_GET_PORT_OK,\n\n    /**\n     * The instance was not bound to any port.\n     */\n    TOX_ERR_GET_PORT_NOT_BOUND,\n\n} TOX_ERR_GET_PORT;\n\n\n/**\n * Return the UDP port this Tox instance is bound to.\n */\nuint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error);\n\n/**\n * Return the TCP port this Tox instance is bound to. This is only relevant if\n * the instance is acting as a TCP relay.\n */\nuint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error);\n\n#include \"tox_old.h\"\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "toxcore/tox_old.h",
    "content": "/**********GROUP CHAT FUNCTIONS ************/\n\n/* Group chat types for tox_callback_group_invite function.\n *\n * TOX_GROUPCHAT_TYPE_TEXT groupchats must be accepted with the tox_join_groupchat() function.\n * The function to accept TOX_GROUPCHAT_TYPE_AV is in toxav.\n */\nenum {\n    TOX_GROUPCHAT_TYPE_TEXT,\n    TOX_GROUPCHAT_TYPE_AV\n};\n\n/* Set the callback for group invites.\n *\n *  Function(Tox *tox, int32_t friendnumber, uint8_t type, const uint8_t *data, uint16_t length, void *userdata)\n *\n * data of length is what needs to be passed to join_groupchat().\n *\n * for what type means see the enum right above this comment.\n */\nvoid tox_callback_group_invite(Tox *tox, void (*function)(Tox *tox, int32_t, uint8_t, const uint8_t *, uint16_t,\n                               void *), void *userdata);\n\n/* Set the callback for group messages.\n *\n *  Function(Tox *tox, int groupnumber, int peernumber, const uint8_t * message, uint16_t length, void *userdata)\n */\nvoid tox_callback_group_message(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *),\n                                void *userdata);\n\n/* Set the callback for group actions.\n *\n *  Function(Tox *tox, int groupnumber, int peernumber, const uint8_t * action, uint16_t length, void *userdata)\n */\nvoid tox_callback_group_action(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint16_t, void *),\n                               void *userdata);\n\n/* Set callback function for title changes.\n *\n * Function(Tox *tox, int groupnumber, int peernumber, uint8_t * title, uint8_t length, void *userdata)\n * if peernumber == -1, then author is unknown (e.g. initial joining the group)\n */\nvoid tox_callback_group_title(Tox *tox, void (*function)(Tox *tox, int, int, const uint8_t *, uint8_t,\n                              void *), void *userdata);\n\n/* Set callback function for peer name list changes.\n *\n * It gets called every time the name list changes(new peer/name, deleted peer)\n *  Function(Tox *tox, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata)\n */\ntypedef enum {\n    TOX_CHAT_CHANGE_PEER_ADD,\n    TOX_CHAT_CHANGE_PEER_DEL,\n    TOX_CHAT_CHANGE_PEER_NAME,\n} TOX_CHAT_CHANGE;\n\nvoid tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *),\n                                        void *userdata);\n\n/* Creates a new groupchat and puts it in the chats array.\n *\n * return group number on success.\n * return -1 on failure.\n */\nint tox_add_groupchat(Tox *tox);\n\n/* Delete a groupchat from the chats array.\n *\n * return 0 on success.\n * return -1 if failure.\n */\nint tox_del_groupchat(Tox *tox, int groupnumber);\n\n/* Copy the name of peernumber who is in groupnumber to name.\n * name must be at least TOX_MAX_NAME_LENGTH long.\n *\n * return length of name if success\n * return -1 if failure\n */\nint tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name);\n\n/* Copy the public key of peernumber who is in groupnumber to public_key.\n * public_key must be TOX_PUBLIC_KEY_SIZE long.\n *\n * returns 0 on success\n * returns -1 on failure\n */\nint tox_group_peer_pubkey(const Tox *tox, int groupnumber, int peernumber, uint8_t *public_key);\n\n/* invite friendnumber to groupnumber\n * return 0 on success\n * return -1 on failure\n */\nint tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber);\n\n/* Join a group (you need to have been invited first.) using data of length obtained\n * in the group invite callback.\n *\n * returns group number on success\n * returns -1 on failure.\n */\nint tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length);\n\n/* send a group message\n * return 0 on success\n * return -1 on failure\n */\nint tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length);\n\n/* send a group action\n * return 0 on success\n * return -1 on failure\n */\nint tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length);\n\n/* set the group's title, limited to MAX_NAME_LENGTH\n * return 0 on success\n * return -1 on failure\n */\nint tox_group_set_title(Tox *tox, int groupnumber, const uint8_t *title, uint8_t length);\n\n/* Get group title from groupnumber and put it in title.\n * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes.\n *\n *  return length of copied title if success.\n *  return -1 if failure.\n */\nint tox_group_get_title(Tox *tox, int groupnumber, uint8_t *title, uint32_t max_length);\n\n/* Check if the current peernumber corresponds to ours.\n *\n * return 1 if the peernumber corresponds to ours.\n * return 0 on failure.\n */\nunsigned int tox_group_peernumber_is_ours(const Tox *tox, int groupnumber, int peernumber);\n\n/* Return the number of peers in the group chat on success.\n * return -1 on failure\n */\nint tox_group_number_peers(const Tox *tox, int groupnumber);\n\n/* List all the peers in the group chat.\n *\n * Copies the names of the peers to the name[length][TOX_MAX_NAME_LENGTH] array.\n *\n * Copies the lengths of the names to lengths[length]\n *\n * returns the number of peers on success.\n *\n * return -1 on failure.\n */\nint tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[],\n                        uint16_t length);\n\n/* Return the number of chats in the instance m.\n * You should use this to determine how much memory to allocate\n * for copy_chatlist. */\nuint32_t tox_count_chatlist(const Tox *tox);\n\n/* Copy a list of valid chat IDs into the array out_list.\n * If out_list is NULL, returns 0.\n * Otherwise, returns the number of elements copied.\n * If the array was too small, the contents\n * of out_list will be truncated to list_size. */\nuint32_t tox_get_chatlist(const Tox *tox, int32_t *out_list, uint32_t list_size);\n\n/* return the type of groupchat (TOX_GROUPCHAT_TYPE_) that groupnumber is.\n *\n * return -1 on failure.\n * return type on success.\n */\nint tox_group_get_type(const Tox *tox, int groupnumber);\n\n"
  },
  {
    "path": "toxcore/tox_old_code.h",
    "content": "/**********GROUP CHAT FUNCTIONS: WARNING Group chats will be rewritten so this might change ************/\n\n/* Set the callback for group invites.\n *\n *  Function(Tox *tox, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata)\n *\n * data of length is what needs to be passed to join_groupchat().\n */\nvoid tox_callback_group_invite(Tox *tox, void (*function)(Messenger *tox, int32_t, uint8_t, const uint8_t *, uint16_t,\n                               void *), void *userdata)\n{\n    Messenger *m = tox;\n    g_callback_group_invite(m->group_chat_object, function, userdata);\n}\n\n/* Set the callback for group messages.\n *\n *  Function(Tox *tox, int groupnumber, int peernumber, uint8_t * message, uint16_t length, void *userdata)\n */\nvoid tox_callback_group_message(Tox *tox, void (*function)(Messenger *tox, int, int, const uint8_t *, uint16_t, void *),\n                                void *userdata)\n{\n    Messenger *m = tox;\n    g_callback_group_message(m->group_chat_object, function, userdata);\n}\n\n/* Set the callback for group actions.\n *\n *  Function(Tox *tox, int groupnumber, int peernumber, uint8_t * action, uint16_t length, void *userdata)\n */\nvoid tox_callback_group_action(Tox *tox, void (*function)(Messenger *tox, int, int, const uint8_t *, uint16_t, void *),\n                               void *userdata)\n{\n    Messenger *m = tox;\n    g_callback_group_action(m->group_chat_object, function, userdata);\n}\n\n/* Set callback function for title changes.\n *\n * Function(Tox *tox, int groupnumber, int peernumber, uint8_t * title, uint8_t length, void *userdata)\n * if peernumber == -1, then author is unknown (e.g. initial joining the group)\n */\nvoid tox_callback_group_title(Tox *tox, void (*function)(Messenger *tox, int, int, const uint8_t *, uint8_t,\n                              void *), void *userdata)\n{\n    Messenger *m = tox;\n    g_callback_group_title(m->group_chat_object, function, userdata);\n}\n\n/* Set callback function for peer name list changes.\n *\n * It gets called every time the name list changes(new peer/name, deleted peer)\n *  Function(Tox *tox, int groupnumber, void *userdata)\n */\nvoid tox_callback_group_namelist_change(Tox *tox, void (*function)(Tox *tox, int, int, uint8_t, void *), void *userdata)\n{\n    Messenger *m = tox;\n    g_callback_group_namelistchange(m->group_chat_object, function, userdata);\n}\n\n/* Creates a new groupchat and puts it in the chats array.\n *\n * return group number on success.\n * return -1 on failure.\n */\nint tox_add_groupchat(Tox *tox)\n{\n    Messenger *m = tox;\n    return add_groupchat(m->group_chat_object, GROUPCHAT_TYPE_TEXT);\n}\n\n/* Delete a groupchat from the chats array.\n *\n * return 0 on success.\n * return -1 if failure.\n */\nint tox_del_groupchat(Tox *tox, int groupnumber)\n{\n    Messenger *m = tox;\n    return del_groupchat(m->group_chat_object, groupnumber);\n}\n\n/* Copy the name of peernumber who is in groupnumber to name.\n * name must be at least MAX_NICK_BYTES long.\n *\n * return length of name if success\n * return -1 if failure\n */\nint tox_group_peername(const Tox *tox, int groupnumber, int peernumber, uint8_t *name)\n{\n    const Messenger *m = tox;\n    return group_peername(m->group_chat_object, groupnumber, peernumber, name);\n}\n\n/* Copy the public key of peernumber who is in groupnumber to public_key.\n * public_key must be crypto_box_PUBLICKEYBYTES long.\n *\n * returns 0 on success\n * returns -1 on failure\n */\nint tox_group_peer_pubkey(const Tox *tox, int groupnumber, int peernumber, uint8_t *public_key)\n{\n    const Messenger *m = tox;\n    return group_peer_pubkey(m->group_chat_object, groupnumber, peernumber, public_key);\n}\n\n/* invite friendnumber to groupnumber\n * return 0 on success\n * return -1 on failure\n */\nint tox_invite_friend(Tox *tox, int32_t friendnumber, int groupnumber)\n{\n    Messenger *m = tox;\n    return invite_friend(m->group_chat_object, friendnumber, groupnumber);\n}\n\n/* Join a group (you need to have been invited first.) using data of length obtained\n * in the group invite callback.\n *\n * returns group number on success\n * returns -1 on failure.\n */\nint tox_join_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length)\n{\n    Messenger *m = tox;\n    return join_groupchat(m->group_chat_object, friendnumber, GROUPCHAT_TYPE_TEXT, data, length);\n}\n\n/* send a group message\n * return 0 on success\n * return -1 on failure\n */\nint tox_group_message_send(Tox *tox, int groupnumber, const uint8_t *message, uint16_t length)\n{\n    Messenger *m = tox;\n    return group_message_send(m->group_chat_object, groupnumber, message, length);\n}\n\n/* send a group action\n * return 0 on success\n * return -1 on failure\n */\nint tox_group_action_send(Tox *tox, int groupnumber, const uint8_t *action, uint16_t length)\n{\n    Messenger *m = tox;\n    return group_action_send(m->group_chat_object, groupnumber, action, length);\n}\n\n/* set the group's title, limited to MAX_NAME_LENGTH\n * return 0 on success\n * return -1 on failure\n */\nint tox_group_set_title(Tox *tox, int groupnumber, const uint8_t *title, uint8_t length)\n{\n    Messenger *m = tox;\n    return group_title_send(m->group_chat_object, groupnumber, title, length);\n}\n\n/* Get group title from groupnumber and put it in title.\n * title needs to be a valid memory location with a max_length size of at least MAX_NAME_LENGTH (128) bytes.\n *\n *  return length of copied title if success.\n *  return -1 if failure.\n */\nint tox_group_get_title(Tox *tox, int groupnumber, uint8_t *title, uint32_t max_length)\n{\n    Messenger *m = tox;\n    return group_title_get(m->group_chat_object, groupnumber, title, max_length);\n}\n\n/* Check if the current peernumber corresponds to ours.\n *\n * return 1 if the peernumber corresponds to ours.\n * return 0 on failure.\n */\nunsigned int tox_group_peernumber_is_ours(const Tox *tox, int groupnumber, int peernumber)\n{\n    const Messenger *m = tox;\n    return group_peernumber_is_ours(m->group_chat_object, groupnumber, peernumber);\n}\n\n/* Return the number of peers in the group chat on success.\n * return -1 on failure\n */\nint tox_group_number_peers(const Tox *tox, int groupnumber)\n{\n    const Messenger *m = tox;\n    return group_number_peers(m->group_chat_object, groupnumber);\n}\n\n/* List all the peers in the group chat.\n *\n * Copies the names of the peers to the name[length][MAX_NICK_BYTES] array.\n *\n * Copies the lengths of the names to lengths[length]\n *\n * returns the number of peers on success.\n *\n * return -1 on failure.\n */\nint tox_group_get_names(const Tox *tox, int groupnumber, uint8_t names[][TOX_MAX_NAME_LENGTH], uint16_t lengths[],\n                        uint16_t length)\n{\n    const Messenger *m = tox;\n    return group_names(m->group_chat_object, groupnumber, names, lengths, length);\n}\n\n/* Return the number of chats in the instance m.\n * You should use this to determine how much memory to allocate\n * for copy_chatlist. */\nuint32_t tox_count_chatlist(const Tox *tox)\n{\n    const Messenger *m = tox;\n    return count_chatlist(m->group_chat_object);\n}\n\n/* Copy a list of valid chat IDs into the array out_list.\n * If out_list is NULL, returns 0.\n * Otherwise, returns the number of elements copied.\n * If the array was too small, the contents\n * of out_list will be truncated to list_size. */\nuint32_t tox_get_chatlist(const Tox *tox, int32_t *out_list, uint32_t list_size)\n{\n    const Messenger *m = tox;\n    return copy_chatlist(m->group_chat_object, out_list, list_size);\n}\n\n/* return the type of groupchat (TOX_GROUPCHAT_TYPE_) that groupnumber is.\n *\n * return -1 on failure.\n * return type on success.\n */\nint tox_group_get_type(const Tox *tox, int groupnumber)\n{\n    const Messenger *m = tox;\n    return group_get_type(m->group_chat_object, groupnumber);\n}\n"
  },
  {
    "path": "toxcore/util.c",
    "content": "/*\n * util.c -- Utilities.\n *\n * This file is donated to the Tox Project.\n * Copyright 2013  plutooo\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <time.h>\n\n/* for crypto_box_PUBLICKEYBYTES */\n#include \"crypto_core.h\"\n\n#include \"util.h\"\n\n\n/* don't call into system billions of times for no reason */\nstatic uint64_t unix_time_value;\nstatic uint64_t unix_base_time_value;\n\nvoid unix_time_update()\n{\n    if (unix_base_time_value == 0)\n        unix_base_time_value = ((uint64_t)time(NULL) - (current_time_monotonic() / 1000ULL));\n\n    unix_time_value = (current_time_monotonic() / 1000ULL) + unix_base_time_value;\n}\n\nuint64_t unix_time()\n{\n    return unix_time_value;\n}\n\nint is_timeout(uint64_t timestamp, uint64_t timeout)\n{\n    return timestamp + timeout <= unix_time();\n}\n\n\n/* id functions */\nbool id_equal(const uint8_t *dest, const uint8_t *src)\n{\n    return public_key_cmp(dest, src) == 0;\n}\n\nuint32_t id_copy(uint8_t *dest, const uint8_t *src)\n{\n    memcpy(dest, src, crypto_box_PUBLICKEYBYTES);\n    return crypto_box_PUBLICKEYBYTES;\n}\n\nvoid host_to_net(uint8_t *num, uint16_t numbytes)\n{\n#ifndef WORDS_BIGENDIAN\n    uint32_t i;\n    uint8_t buff[numbytes];\n\n    for (i = 0; i < numbytes; ++i) {\n        buff[i] = num[numbytes - i - 1];\n    }\n\n    memcpy(num, buff, numbytes);\n#endif\n    return;\n}\n\nuint16_t lendian_to_host16(uint16_t lendian)\n{\n#ifdef WORDS_BIGENDIAN\n    return  (lendian << 8) | (lendian >> 8 );\n#else\n    return lendian;\n#endif\n}\n\nvoid host_to_lendian32(uint8_t *dest,  uint32_t num)\n{\n#ifdef WORDS_BIGENDIAN\n    num = ((num << 8) & 0xFF00FF00 ) | ((num >> 8) & 0xFF00FF );\n    num = (num << 16) | (num >> 16);\n#endif\n    memcpy(dest, &num, sizeof(uint32_t));\n}\n\nvoid lendian_to_host32(uint32_t *dest, const uint8_t *lendian)\n{\n    uint32_t d;\n    memcpy(&d, lendian, sizeof(uint32_t));\n#ifdef WORDS_BIGENDIAN\n    d = ((d << 8) & 0xFF00FF00 ) | ((d >> 8) & 0xFF00FF );\n    d = (d << 16) | (d >> 16);\n#endif\n    *dest = d;\n}\n\n/* state load/save */\nint load_state(load_state_callback_func load_state_callback, void *outer,\n               const uint8_t *data, uint32_t length, uint16_t cookie_inner)\n{\n    if (!load_state_callback || !data) {\n#ifdef DEBUG\n        fprintf(stderr, \"load_state() called with invalid args.\\n\");\n#endif\n        return -1;\n    }\n\n\n    uint16_t type;\n    uint32_t length_sub, cookie_type;\n    uint32_t size_head = sizeof(uint32_t) * 2;\n\n    while (length >= size_head) {\n        lendian_to_host32(&length_sub, data);\n        lendian_to_host32(&cookie_type, data + sizeof(length_sub));\n        data += size_head;\n        length -= size_head;\n\n        if (length < length_sub) {\n            /* file truncated */\n#ifdef DEBUG\n            fprintf(stderr, \"state file too short: %u < %u\\n\", length, length_sub);\n#endif\n            return -1;\n        }\n\n        if (lendian_to_host16((cookie_type >> 16)) != cookie_inner) {\n            /* something is not matching up in a bad way, give up */\n#ifdef DEBUG\n            fprintf(stderr, \"state file garbeled: %04hx != %04hx\\n\", (cookie_type >> 16), cookie_inner);\n#endif\n            return -1;\n        }\n\n        type = lendian_to_host16(cookie_type & 0xFFFF);\n\n        int ret = load_state_callback(outer, data, length_sub, type);\n\n        if (ret == -1) {\n            return -1;\n        }\n\n        /* -2 means end of save. */\n        if (ret == -2)\n            return 0;\n\n        data += length_sub;\n        length -= length_sub;\n    }\n\n    return length == 0 ? 0 : -1;\n};\n\nint create_recursive_mutex(pthread_mutex_t *mutex)\n{\n    pthread_mutexattr_t attr;\n\n    if (pthread_mutexattr_init(&attr) != 0)\n        return -1;\n\n    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {\n        pthread_mutexattr_destroy(&attr);\n        return -1;\n    }\n\n    /* Create queue mutex */\n    if (pthread_mutex_init(mutex, &attr) != 0) {\n        pthread_mutexattr_destroy(&attr);\n        return -1;\n    }\n\n    pthread_mutexattr_destroy(&attr);\n\n    return 0;\n}\n\n\nstruct RingBuffer {\n    uint16_t size; /* Max size */\n    uint16_t start;\n    uint16_t end;\n    void   **data;\n};\n\nbool rb_full(const RingBuffer *b)\n{\n    return (b->end + 1) % b->size == b->start;\n}\nbool rb_empty(const RingBuffer *b)\n{\n    return b->end == b->start;\n}\nvoid *rb_write(RingBuffer *b, void *p)\n{\n    void *rc = NULL;\n\n    if ((b->end + 1) % b->size == b->start) /* full */\n        rc = b->data[b->start];\n\n    b->data[b->end] = p;\n    b->end = (b->end + 1) % b->size;\n\n    if (b->end == b->start)\n        b->start = (b->start + 1) % b->size;\n\n    return rc;\n}\nbool rb_read(RingBuffer *b, void **p)\n{\n    if (b->end == b->start) { /* Empty */\n        *p = NULL;\n        return false;\n    }\n\n    *p = b->data[b->start];\n    b->start = (b->start + 1) % b->size;\n    return true;\n}\nRingBuffer *rb_new(int size)\n{\n    RingBuffer *buf = calloc(sizeof(RingBuffer), 1);\n\n    if (!buf) return NULL;\n\n    buf->size = size + 1; /* include empty elem */\n\n    if (!(buf->data = calloc(buf->size, sizeof(void *)))) {\n        free(buf);\n        return NULL;\n    }\n\n    return buf;\n}\nvoid rb_kill(RingBuffer *b)\n{\n    if (b) {\n        free(b->data);\n        free(b);\n    }\n}\nuint16_t rb_size(const RingBuffer *b)\n{\n    if (rb_empty(b))\n        return 0;\n\n    return\n        b->end > b->start ?\n        b->end - b->start :\n        (b->size - b->start) + b->end;\n}\nuint16_t rb_data(const RingBuffer *b, void **dest)\n{\n    uint16_t i = 0;\n\n    for (; i < rb_size(b); i++)\n        dest[i] = b->data[(b->start + i) % b->size];\n\n    return i;\n}\n"
  },
  {
    "path": "toxcore/util.h",
    "content": "/*\n * util.h -- Utilities.\n *\n * This file is donated to the Tox Project.\n * Copyright 2013  plutooo\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __UTIL_H__\n#define __UTIL_H__\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <pthread.h>\n\n#define MIN(a,b) (((a)<(b))?(a):(b))\n#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }\n\nvoid unix_time_update();\nuint64_t unix_time();\nint is_timeout(uint64_t timestamp, uint64_t timeout);\n\n\n/* id functions */\nbool id_equal(const uint8_t *dest, const uint8_t *src);\nuint32_t id_copy(uint8_t *dest, const uint8_t *src); /* return value is CLIENT_ID_SIZE */\n\nvoid host_to_net(uint8_t *num, uint16_t numbytes);\n#define net_to_host(x, y) host_to_net(x, y)\n\nuint16_t lendian_to_host16(uint16_t lendian);\n#define host_tolendian16(x) lendian_to_host16(x)\n\nvoid host_to_lendian32(uint8_t *dest,  uint32_t num);\nvoid lendian_to_host32(uint32_t *dest, const uint8_t *lendian);\n\n/* state load/save */\ntypedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type);\nint load_state(load_state_callback_func load_state_callback, void *outer,\n               const uint8_t *data, uint32_t length, uint16_t cookie_inner);\n\n/* Returns -1 if failed or 0 if success */\nint create_recursive_mutex(pthread_mutex_t *mutex);\n\n/* Ring buffer */\ntypedef struct RingBuffer RingBuffer;\nbool rb_full(const RingBuffer *b);\nbool rb_empty(const RingBuffer *b);\nvoid *rb_write(RingBuffer *b, void *p);\nbool rb_read(RingBuffer *b, void **p);\nRingBuffer *rb_new(int size);\nvoid rb_kill(RingBuffer *b);\nuint16_t rb_size(const RingBuffer *b);\nuint16_t rb_data(const RingBuffer *b, void **dest);\n\n#endif /* __UTIL_H__ */\n"
  },
  {
    "path": "toxdns/Makefile.inc",
    "content": "lib_LTLIBRARIES += libtoxdns.la\n\nlibtoxdns_la_include_HEADERS = \\\n                        ../toxdns/toxdns.h\n\nlibtoxdns_la_includedir = $(includedir)/tox\n\nlibtoxdns_la_SOURCES =  ../toxdns/toxdns.h \\\n                        ../toxdns/toxdns.c\n\nlibtoxdns_la_CFLAGS =   -I$(top_srcdir) \\\n                        -I$(top_srcdir)/toxcore \\\n                        $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS) \\\n                        $(PTHREAD_CFLAGS)\n\nlibtoxdns_la_LDFLAGS =  $(TOXCORE_LT_LDFLAGS) \\\n                        $(EXTRA_LT_LDFLAGS) \\\n                        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        $(MATH_LDFLAGS) \\\n                        $(RT_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\nlibtoxdns_la_LIBADD =   $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NAC_LIBS) \\\n                        $(PTHREAD_LIBS) \\\n                        libtoxcore.la\n"
  },
  {
    "path": "toxdns/toxdns.c",
    "content": "/* toxdns.c\n *\n * Tox secure username DNS toxid resolving functions.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../toxcore/Messenger.h\"\n#include \"../toxcore/logger.h\"\n#include \"toxdns.h\"\n\nstatic const char base32[32] = {\"abcdefghijklmnopqrstuvwxyz012345\"};\n\n#define _encode(a, b, c) \\\n{ \\\nuint8_t i = 0; \\\n    while(i != c) { \\\n        *a++ = base32[((b[0] >> bits) | (b[1] << (8 - bits))) & 0x1F]; \\\n        bits += 5; \\\n        if(bits >= 8) { \\\n            bits -= 8; \\\n            b++; \\\n            i++; \\\n        } \\\n    } \\\n} \\\n\ntypedef struct {\n    uint8_t temp_pk[crypto_box_PUBLICKEYBYTES];\n    uint8_t temp_sk[crypto_box_SECRETKEYBYTES];\n    uint8_t server_public_key[crypto_box_PUBLICKEYBYTES];\n    uint8_t shared_key[crypto_box_KEYBYTES];\n    uint32_t nonce;\n    uint32_t nonce_start;\n} DNS_Object;\n\nstatic void dns_new_temp_keys(DNS_Object *d)\n{\n    d->nonce = d->nonce_start = random_int();\n    crypto_box_keypair(d->temp_pk, d->temp_sk);\n    encrypt_precompute(d->server_public_key, d->temp_sk, d->shared_key);\n}\n\n/* Create a new tox_dns3 object for server with server_public_key.\n *\n * return Null on failure.\n * return pointer object on success.\n */\nvoid *tox_dns3_new(uint8_t *server_public_key)\n{\n    DNS_Object *d = malloc(sizeof(DNS_Object));\n\n    if (d == NULL)\n        return NULL;\n\n    memcpy(d->server_public_key, server_public_key, crypto_box_PUBLICKEYBYTES);\n    dns_new_temp_keys(d);\n    return d;\n}\n\n/* Destroy the tox dns3 object.\n */\nvoid tox_dns3_kill(void *dns3_object)\n{\n    memset(dns3_object, 0, sizeof(DNS_Object));\n    free(dns3_object);\n}\n\n/* Generate a dns3 string of string_max_len used to query the dns server referred to by to\n * dns3_object for a tox id registered to user with name of name_len.\n *\n * the uint32_t pointed by request_id will be set to the request id which must be passed to\n * tox_decrypt_dns3_TXT() to correctly decode the response.\n *\n * This is what the string returned looks like:\n * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc\n *\n * returns length of string on success.\n * returns -1 on failure.\n */\nint tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id,\n                             uint8_t *name, uint8_t name_len)\n{\n#define DOT_INTERVAL (6 * 5)\n    int base = (sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + name_len + crypto_box_MACBYTES);\n    int end_len = ((base * 8) / 5) + (base / DOT_INTERVAL) + !!(base % 5);\n    end_len -= !(base % DOT_INTERVAL);\n\n    if (end_len > string_max_len)\n        return -1;\n\n    DNS_Object *d = dns3_object;\n    uint8_t buffer[1024];\n    uint8_t nonce[crypto_box_NONCEBYTES] = {0};\n    memcpy(nonce, &d->nonce, sizeof(uint32_t));\n    memcpy(buffer, &d->nonce, sizeof(uint32_t));\n    memcpy(buffer + sizeof(uint32_t), d->temp_pk, crypto_box_PUBLICKEYBYTES);\n    int len = encrypt_data_symmetric(d->shared_key, nonce, name, name_len,\n                                     buffer + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES);\n\n    if (len == -1)\n        return -1;\n\n    int total_len = len + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES;\n    uint8_t *buff = buffer, *old_str = string;\n    buffer[total_len] = 0;\n    uint8_t bits = 0;\n    int i;\n\n    for (i = !(total_len % DOT_INTERVAL); i < (total_len / DOT_INTERVAL); ++i) {\n        _encode(string, buff, DOT_INTERVAL);\n        *string = '.';\n        ++string;\n    }\n\n    int left = total_len - (buff - buffer);\n    _encode(string, buff, left);\n#undef DOT_INTERVAL\n    *request_id = d->nonce;\n    ++d->nonce;\n\n    if (d->nonce == d->nonce_start) {\n        dns_new_temp_keys(d);\n    }\n\n    if (end_len != string - old_str) {\n        LOGGER_ERROR(\"tox_generate_dns3_string Fail, %u != %lu\\n\", end_len, string - old_str);\n        return -1;\n    }\n\n    return string - old_str;\n}\n\n\nstatic int decode(uint8_t *dest, uint8_t *src)\n{\n    uint8_t *p = src, *op = dest, bits = 0;\n    *op = 0;\n\n    while (*p) {\n        uint8_t ch = *p++;\n\n        if ('A' <= ch && ch <= 'Z') {\n            ch = ch - 'A';\n        } else if ('a' <= ch && ch <= 'z') {\n            ch = ch - 'a';\n        } else if ('0' <= ch && ch <= '5') {\n            ch = ch - '0' + 26;\n        } else {\n            return - 1;\n        }\n\n        *op |= (ch << bits);\n        bits += 5;\n\n        if (bits >= 8) {\n            bits -= 8;\n            ++op;\n            *op = (ch >> (5 - bits));\n        }\n    }\n\n    return op - dest;\n}\n\n/* Decode and decrypt the id_record returned of length id_record_len into\n * tox_id (needs to be at least TOX_FRIEND_ADDRESS_SIZE).\n *\n * request_id is the request id given by tox_generate_dns3_string() when creating the request.\n *\n * the id_record passed to this function should look somewhat like this:\n * 2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp\n *\n * returns -1 on failure.\n * returns 0 on success.\n *\n */\nint tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len,\n                         uint32_t request_id)\n{\n    DNS_Object *d = dns3_object;\n\n    if (id_record_len != 87)\n        return -1;\n\n    /*if (id_record_len > 255 || id_record_len <= (sizeof(uint32_t) + crypto_box_MACBYTES))\n        return -1;*/\n\n    uint8_t id_record_null[id_record_len + 1];\n    memcpy(id_record_null, id_record, id_record_len);\n    id_record_null[id_record_len] = 0;\n    uint8_t data[id_record_len];\n    int length = decode(data, id_record_null);\n\n    if (length == -1)\n        return -1;\n\n    uint8_t nonce[crypto_box_NONCEBYTES] = {0};\n    memcpy(nonce, &request_id, sizeof(uint32_t));\n    nonce[sizeof(uint32_t)] = 1;\n    int len = decrypt_data_symmetric(d->shared_key, nonce, data, length, tox_id);\n\n    if (len != FRIEND_ADDRESS_SIZE)\n        return -1;\n\n    return 0;\n}\n"
  },
  {
    "path": "toxdns/toxdns.h",
    "content": "/* toxdns.h\n *\n * Tox secure username DNS toxid resolving functions.\n *\n *  Copyright (C) 2014 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TOXDNS_H\n#define TOXDNS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n\n/* Clients are encouraged to set this as the maximum length names can have. */\n#define TOXDNS_MAX_RECOMMENDED_NAME_LENGTH 32\n\n/* How to use this api to make secure tox dns3 requests:\n *\n * 1. Get the public key of a server that supports tox dns3.\n * 2. use tox_dns3_new() to create a new object to create DNS requests\n * and handle responses for that server.\n * 3. Use tox_generate_dns3_string() to generate a string based on the name we want to query and a request_id\n * that must be stored somewhere for when we want to decrypt the response.\n * 4. take the string and use it for your DNS request like this:\n * _4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc._tox.utox.org\n * 5. The TXT in the DNS you receive should look like this:\n * v=tox3;id=2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp\n * 6. Take the id string and use it with tox_decrypt_dns3_TXT() and the request_id corresponding to the\n * request we stored earlier to get the Tox id returned by the DNS server.\n */\n\n/* Create a new tox_dns3 object for server with server_public_key of size TOX_CLIENT_ID_SIZE.\n *\n * return Null on failure.\n * return pointer object on success.\n */\nvoid *tox_dns3_new(uint8_t *server_public_key);\n\n/* Destroy the tox dns3 object.\n */\nvoid tox_dns3_kill(void *dns3_object);\n\n/* Generate a dns3 string of string_max_len used to query the dns server referred to by to\n * dns3_object for a tox id registered to user with name of name_len.\n *\n * the uint32_t pointed by request_id will be set to the request id which must be passed to\n * tox_decrypt_dns3_TXT() to correctly decode the response.\n *\n * This is what the string returned looks like:\n * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc\n *\n * returns length of string on success.\n * returns -1 on failure.\n */\nint tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id,\n                             uint8_t *name, uint8_t name_len);\n\n/* Decode and decrypt the id_record returned of length id_record_len into\n * tox_id (needs to be at least TOX_FRIEND_ADDRESS_SIZE).\n *\n * request_id is the request id given by tox_generate_dns3_string() when creating the request.\n *\n * the id_record passed to this function should look somewhat like this:\n * 2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp\n *\n * returns -1 on failure.\n * returns 0 on success.\n *\n */\nint tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len,\n                         uint32_t request_id);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/Makefile.inc",
    "content": "lib_LTLIBRARIES += libtoxencryptsave.la\n\nlibtoxencryptsave_la_include_HEADERS = \\\n                        ../toxencryptsave/toxencryptsave.h\n\nlibtoxencryptsave_la_includedir = $(includedir)/tox\n\nlibtoxencryptsave_la_SOURCES = ../toxencryptsave/toxencryptsave.h \\\n                        ../toxencryptsave/toxencryptsave.c \\\n                        ../toxencryptsave/defines.h\n\n\nif WITH_NACL\nlibtoxencryptsave_la_SOURCES += ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c \\\n                        ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c\nendif\n\nlibtoxencryptsave_la_CFLAGS =   -I$(top_srcdir) \\\n                        -I$(top_srcdir)/toxcore \\\n                        $(LIBSODIUM_CFLAGS) \\\n                        $(NACL_CFLAGS) \\\n                        $(PTHREAD_CFLAGS)\n\nlibtoxencryptsave_la_LDFLAGS =  $(TOXCORE_LT_LDFLAGS) \\\n                        $(EXTRA_LT_LDFLAGS) \\\n                        $(LIBSODIUM_LDFLAGS) \\\n                        $(NACL_LDFLAGS) \\\n                        $(MATH_LDFLAGS) \\\n                        $(RT_LIBS) \\\n                        $(WINSOCK2_LIBS)\n\nlibtoxencryptsave_la_LIBADD =   $(LIBSODIUM_LIBS) \\\n                        $(NACL_OBJECTS) \\\n                        $(NAC_LIBS) \\\n                        $(PTHREAD_LIBS) \\\n                        libtoxcore.la\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifndef crypto_pwhash_scryptsalsa208sha256_H\n#define crypto_pwhash_scryptsalsa208sha256_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"export.h\"\n\n#ifdef __cplusplus\n# if __GNUC__\n#  pragma GCC diagnostic ignored \"-Wlong-long\"\n# endif\nextern \"C\" {\n#endif\n\n#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U\nSODIUM_EXPORT\nsize_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void);\n\n#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U\nSODIUM_EXPORT\nsize_t crypto_pwhash_scryptsalsa208sha256_strbytes(void);\n\n#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX \"$7$\"\nSODIUM_EXPORT\nconst char *crypto_pwhash_scryptsalsa208sha256_strprefix(void);\n\n#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288ULL\nSODIUM_EXPORT\nsize_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void);\n\n#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216ULL\nSODIUM_EXPORT\nsize_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void);\n\n#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432ULL\nSODIUM_EXPORT\nsize_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void);\n\n#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824ULL\nSODIUM_EXPORT\nsize_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void);\n\nSODIUM_EXPORT\nint crypto_pwhash_scryptsalsa208sha256(unsigned char * const out,\n                                       unsigned long long outlen,\n                                       const char * const passwd,\n                                       unsigned long long passwdlen,\n                                       const unsigned char * const salt,\n                                       unsigned long long opslimit,\n                                       size_t memlimit);\n\nSODIUM_EXPORT\nint crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES],\n                                           const char * const passwd,\n                                           unsigned long long passwdlen,\n                                           unsigned long long opslimit,\n                                           size_t memlimit);\n\nSODIUM_EXPORT\nint crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],\n                                                  const char * const passwd,\n                                                  unsigned long long passwdlen);\n\nSODIUM_EXPORT\nint crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen,\n                                          const uint8_t * salt, size_t saltlen,\n                                          uint64_t N, uint32_t r, uint32_t p,\n                                          uint8_t * buf, size_t buflen);\n\n#ifdef __cplusplus\n}\n#endif\n\n/* Backward compatibility with version 0.5.0 */\n\n#define crypto_pwhash_scryptxsalsa208sha256_SALTBYTES crypto_pwhash_scryptsalsa208sha256_SALTBYTES\n#define crypto_pwhash_scryptxsalsa208sha256_saltbytes crypto_pwhash_scryptsalsa208sha256_saltbytes\n#define crypto_pwhash_scryptxsalsa208sha256_STRBYTES crypto_pwhash_scryptsalsa208sha256_STRBYTES\n#define crypto_pwhash_scryptxsalsa208sha256_strbytes crypto_pwhash_scryptsalsa208sha256_strbytes\n#define crypto_pwhash_scryptxsalsa208sha256 crypto_pwhash_scryptsalsa208sha256\n#define crypto_pwhash_scryptxsalsa208sha256_str crypto_pwhash_scryptsalsa208sha256_str\n#define crypto_pwhash_scryptxsalsa208sha256_str_verify crypto_pwhash_scryptsalsa208sha256_str_verify\n\n#endif\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2013 Alexander Peslyak\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <string.h>\n\n#include \"crypto_pwhash_scryptsalsa208sha256.h\"\n#include \"crypto_scrypt.h\"\n#include \"runtime.h\"\n#include \"utils.h\"\n\nstatic const char * const itoa64 =\n    \"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n\nstatic uint8_t *\nencode64_uint32(uint8_t * dst, size_t dstlen, uint32_t src, uint32_t srcbits)\n{\n    uint32_t bit;\n\n    for (bit = 0; bit < srcbits; bit += 6) {\n        if (dstlen < 1) {\n            return NULL;\n        }\n        *dst++ = itoa64[src & 0x3f];\n        dstlen--;\n        src >>= 6;\n    }\n\n    return dst;\n}\n\nstatic uint8_t *\nencode64(uint8_t * dst, size_t dstlen, const uint8_t * src, size_t srclen)\n{\n    size_t i;\n\n    for (i = 0; i < srclen; ) {\n        uint8_t * dnext;\n        uint32_t value = 0, bits = 0;\n        do {\n            value |= (uint32_t)src[i++] << bits;\n            bits += 8;\n        } while (bits < 24 && i < srclen);\n        dnext = encode64_uint32(dst, dstlen, value, bits);\n        if (!dnext) {\n            return NULL;\n        }\n        dstlen -= dnext - dst;\n        dst = dnext;\n    }\n\n    return dst;\n}\n\nstatic int\ndecode64_one(uint32_t * dst, uint8_t src)\n{\n    const char *ptr = strchr(itoa64, src);\n\n    if (ptr) {\n        *dst = ptr - itoa64;\n        return 0;\n    }\n    *dst = 0;\n    return -1;\n}\n\nstatic const uint8_t *\ndecode64_uint32(uint32_t * dst, uint32_t dstbits, const uint8_t * src)\n{\n    uint32_t bit;\n    uint32_t value;\n\n    value = 0;\n    for (bit = 0; bit < dstbits; bit += 6) {\n        uint32_t one;\n        if (decode64_one(&one, *src)) {\n            *dst = 0;\n            return NULL;\n        }\n        src++;\n        value |= one << bit;\n    }\n\n    *dst = value;\n    return src;\n}\n\nuint8_t *\nescrypt_r(escrypt_local_t * local, const uint8_t * passwd, size_t passwdlen,\n          const uint8_t * setting, uint8_t * buf, size_t buflen)\n{\n    uint8_t        hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES];\n    escrypt_kdf_t  escrypt_kdf;\n    const uint8_t *src;\n    const uint8_t *salt;\n    uint8_t       *dst;\n    size_t         prefixlen;\n    size_t         saltlen;\n    size_t         need;\n    uint64_t       N;\n    uint32_t       N_log2;\n    uint32_t       r;\n    uint32_t       p;\n\n    if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') {\n        return NULL;\n    }\n    src = setting + 3;\n\n    if (decode64_one(&N_log2, *src)) {\n        return NULL;\n    }\n    src++;\n    N = (uint64_t)1 << N_log2;\n\n    src = decode64_uint32(&r, 30, src);\n    if (!src) {\n        return NULL;\n    }\n    src = decode64_uint32(&p, 30, src);\n    if (!src) {\n        return NULL;\n    }\n    prefixlen = src - setting;\n\n    salt = src;\n    src = (uint8_t *) strrchr((char *)salt, '$');\n    if (src) {\n        saltlen = src - salt;\n    } else {\n        saltlen = strlen((char *)salt);\n    }\n    need = prefixlen + saltlen + 1 +\n        crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1;\n    if (need > buflen || need < saltlen) {\n        return NULL;\n    }\n#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER)\n    escrypt_kdf =\n        sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse;\n#else\n    escrypt_kdf = escrypt_kdf_nosse;\n#endif\n    if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen,\n                    N, r, p, hash, sizeof(hash))) {\n        return NULL;\n    }\n\n    dst = buf;\n    memcpy(dst, setting, prefixlen + saltlen);\n    dst += prefixlen + saltlen;\n    *dst++ = '$';\n\n    dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash));\n    sodium_memzero(hash, sizeof hash);\n    if (!dst || dst >= buf + buflen) { /* Can't happen */\n        return NULL;\n    }\n    *dst = 0; /* NUL termination */\n\n    return buf;\n}\n\nuint8_t *\nescrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p,\n                  const uint8_t * src, size_t srclen,\n                  uint8_t * buf, size_t buflen)\n{\n    uint8_t *dst;\n    size_t   prefixlen =\n        (sizeof \"$7$\" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */);\n    size_t   saltlen = BYTES2CHARS(srclen);\n    size_t   need;\n\n    need = prefixlen + saltlen + 1;\n    if (need > buflen || need < saltlen || saltlen < srclen) {\n        return NULL;\n    }\n    if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) {\n        return NULL;\n    }\n    dst = buf;\n    *dst++ = '$';\n    *dst++ = '7';\n    *dst++ = '$';\n\n    *dst++ = itoa64[N_log2];\n\n    dst = encode64_uint32(dst, buflen - (dst - buf), r, 30);\n    if (!dst) { /* Can't happen */\n        return NULL;\n    }\n    dst = encode64_uint32(dst, buflen - (dst - buf), p, 30);\n    if (!dst) { /* Can't happen */\n        return NULL;\n    }\n    dst = encode64(dst, buflen - (dst - buf), src, srclen);\n    if (!dst || dst >= buf + buflen) { /* Can't happen */\n        return NULL;\n    }\n    *dst = 0; /* NUL termination */\n\n    return buf;\n}\n\nint\ncrypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen,\n                                      const uint8_t * salt, size_t saltlen,\n                                      uint64_t N, uint32_t r, uint32_t p,\n                                      uint8_t * buf, size_t buflen)\n{\n    escrypt_kdf_t   escrypt_kdf;\n    escrypt_local_t local;\n    int             retval;\n\n    if (escrypt_init_local(&local)) {\n        return -1;\n    }\n#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER)\n    escrypt_kdf =\n        sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse;\n#else\n    escrypt_kdf = escrypt_kdf_nosse;\n#endif\n    retval = escrypt_kdf(&local,\n                         passwd, passwdlen, salt, saltlen,\n                         N, r, p, buf, buflen);\n    if (escrypt_free_local(&local)) {\n        return -1;\n    }\n    return retval;\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2009 Colin Percival\n * Copyright 2013 Alexander Peslyak\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * This file was originally written by Colin Percival as part of the Tarsnap\n * online backup system.\n */\n#ifndef _CRYPTO_SCRYPT_H_\n#define _CRYPTO_SCRYPT_H_\n\n#include <stdint.h>\n\n#define crypto_pwhash_scryptsalsa208sha256_STRPREFIXBYTES 14\n#define crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES 57\n#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES 32\n#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES_ENCODED 43\n#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES 32\n#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED 43\n\n#define BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6)\n\ntypedef struct {\n\tvoid * base, * aligned;\n\tsize_t size;\n} escrypt_region_t;\n\ntypedef escrypt_region_t escrypt_local_t;\n\nextern int escrypt_init_local(escrypt_local_t * __local);\n\nextern int escrypt_free_local(escrypt_local_t * __local);\n\nextern void *alloc_region(escrypt_region_t * region, size_t size);\nextern int free_region(escrypt_region_t * region);\n\ntypedef int (*escrypt_kdf_t)(escrypt_local_t * __local,\n                             const uint8_t * __passwd, size_t __passwdlen,\n                             const uint8_t * __salt, size_t __saltlen,\n                             uint64_t __N, uint32_t __r, uint32_t __p,\n                             uint8_t * __buf, size_t __buflen);\n\nextern int escrypt_kdf_nosse(escrypt_local_t * __local,\n    const uint8_t * __passwd, size_t __passwdlen,\n    const uint8_t * __salt, size_t __saltlen,\n    uint64_t __N, uint32_t __r, uint32_t __p,\n    uint8_t * __buf, size_t __buflen);\n\nextern int escrypt_kdf_sse(escrypt_local_t * __local,\n    const uint8_t * __passwd, size_t __passwdlen,\n    const uint8_t * __salt, size_t __saltlen,\n    uint64_t __N, uint32_t __r, uint32_t __p,\n    uint8_t * __buf, size_t __buflen);\n\nextern uint8_t * escrypt_r(escrypt_local_t * __local,\n    const uint8_t * __passwd, size_t __passwdlen,\n    const uint8_t * __setting,\n    uint8_t * __buf, size_t __buflen);\n\nextern uint8_t * escrypt_gensalt_r(\n    uint32_t __N_log2, uint32_t __r, uint32_t __p,\n    const uint8_t * __src, size_t __srclen,\n    uint8_t * __buf, size_t __buflen);\n\n#endif /* !_CRYPTO_SCRYPT_H_ */\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifndef __SODIUM_EXPORT_H__\n#define __SODIUM_EXPORT_H__\n\n#ifndef __GNUC__\n# ifdef __attribute__\n#  undef __attribute__\n# endif\n# define __attribute__(a)\n#endif\n\n#ifdef SODIUM_STATIC\n# define SODIUM_EXPORT\n#else\n# if defined(_MSC_VER)\n#  ifdef DLL_EXPORT\n#   define SODIUM_EXPORT __declspec(dllexport)\n#  else\n#   define SODIUM_EXPORT __declspec(dllimport)\n#  endif\n# else\n#  if defined(__SUNPRO_C)\n#   define SODIUM_EXPORT __attribute__ __global\n#  elif defined(_MSG_VER)\n#   define SODIUM_EXPORT extern __declspec(dllexport)\n#  else\n#   define SODIUM_EXPORT __attribute__ ((visibility (\"default\")))\n#  endif\n# endif\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2009 Colin Percival\n * Copyright 2013 Alexander Peslyak\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * This file was originally written by Colin Percival as part of the Tarsnap\n * online backup system.\n */\n\n#include <errno.h>\n#include <limits.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"../pbkdf2-sha256.h\"\n#include \"../sysendian.h\"\n#include \"../crypto_scrypt.h\"\n\nstatic inline void\nblkcpy(void * dest, const void * src, size_t len)\n{\n\tsize_t * D = (size_t *) dest;\n\tconst size_t * S = (const size_t *) src;\n\tsize_t L = len / sizeof(size_t);\n\tsize_t i;\n\n\tfor (i = 0; i < L; i++)\n\t\tD[i] = S[i];\n}\n\nstatic inline void\nblkxor(void * dest, const void * src, size_t len)\n{\n\tsize_t * D = (size_t *) dest;\n\tconst size_t * S = (const size_t *) src;\n\tsize_t L = len / sizeof(size_t);\n\tsize_t i;\n\n\tfor (i = 0; i < L; i++)\n\t\tD[i] ^= S[i];\n}\n\n/**\n * salsa20_8(B):\n * Apply the salsa20/8 core to the provided block.\n */\nstatic void\nsalsa20_8(uint32_t B[16])\n{\n\tuint32_t x[16];\n\tsize_t i;\n\n\tblkcpy(x, B, 64);\n\tfor (i = 0; i < 8; i += 2) {\n#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))\n\t\t/* Operate on columns. */\n\t\tx[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);\n\t\tx[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);\n\n\t\tx[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);\n\t\tx[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);\n\n\t\tx[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);\n\t\tx[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);\n\n\t\tx[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);\n\t\tx[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);\n\n\t\t/* Operate on rows. */\n\t\tx[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);\n\t\tx[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);\n\n\t\tx[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);\n\t\tx[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);\n\n\t\tx[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);\n\t\tx[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);\n\n\t\tx[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);\n\t\tx[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);\n#undef R\n\t}\n\tfor (i = 0; i < 16; i++)\n\t\tB[i] += x[i];\n}\n\n/**\n * blockmix_salsa8(Bin, Bout, X, r):\n * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r\n * bytes in length; the output Bout must also be the same size.  The\n * temporary space X must be 64 bytes.\n */\nstatic void\nblockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r)\n{\n\tsize_t i;\n\n\t/* 1: X <-- B_{2r - 1} */\n\tblkcpy(X, &Bin[(2 * r - 1) * 16], 64);\n\n\t/* 2: for i = 0 to 2r - 1 do */\n\tfor (i = 0; i < 2 * r; i += 2) {\n\t\t/* 3: X <-- H(X \\xor B_i) */\n\t\tblkxor(X, &Bin[i * 16], 64);\n\t\tsalsa20_8(X);\n\n\t\t/* 4: Y_i <-- X */\n\t\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\t\tblkcpy(&Bout[i * 8], X, 64);\n\n\t\t/* 3: X <-- H(X \\xor B_i) */\n\t\tblkxor(X, &Bin[i * 16 + 16], 64);\n\t\tsalsa20_8(X);\n\n\t\t/* 4: Y_i <-- X */\n\t\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\t\tblkcpy(&Bout[i * 8 + r * 16], X, 64);\n\t}\n}\n\n/**\n * integerify(B, r):\n * Return the result of parsing B_{2r-1} as a little-endian integer.\n */\nstatic inline uint64_t\nintegerify(const void * B, size_t r)\n{\n\tconst uint32_t * X = (const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64);\n\n\treturn (((uint64_t)(X[1]) << 32) + X[0]);\n}\n\n/**\n * smix(B, r, N, V, XY):\n * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;\n * the temporary storage V must be 128rN bytes in length; the temporary\n * storage XY must be 256r + 64 bytes in length.  The value N must be a\n * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a\n * multiple of 64 bytes.\n */\nstatic void\nsmix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY)\n{\n\tuint32_t * X = XY;\n\tuint32_t * Y = &XY[32 * r];\n\tuint32_t * Z = &XY[64 * r];\n\tuint64_t i;\n\tuint64_t j;\n\tsize_t k;\n\n\t/* 1: X <-- B */\n\tfor (k = 0; k < 32 * r; k++)\n\t\tX[k] = le32dec(&B[4 * k]);\n\n\t/* 2: for i = 0 to N - 1 do */\n\tfor (i = 0; i < N; i += 2) {\n\t\t/* 3: V_i <-- X */\n\t\tblkcpy(&V[i * (32 * r)], X, 128 * r);\n\n\t\t/* 4: X <-- H(X) */\n\t\tblockmix_salsa8(X, Y, Z, r);\n\n\t\t/* 3: V_i <-- X */\n\t\tblkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);\n\n\t\t/* 4: X <-- H(X) */\n\t\tblockmix_salsa8(Y, X, Z, r);\n\t}\n\n\t/* 6: for i = 0 to N - 1 do */\n\tfor (i = 0; i < N; i += 2) {\n\t\t/* 7: j <-- Integerify(X) mod N */\n\t\tj = integerify(X, r) & (N - 1);\n\n\t\t/* 8: X <-- H(X \\xor V_j) */\n\t\tblkxor(X, &V[j * (32 * r)], 128 * r);\n\t\tblockmix_salsa8(X, Y, Z, r);\n\n\t\t/* 7: j <-- Integerify(X) mod N */\n\t\tj = integerify(Y, r) & (N - 1);\n\n\t\t/* 8: X <-- H(X \\xor V_j) */\n\t\tblkxor(Y, &V[j * (32 * r)], 128 * r);\n\t\tblockmix_salsa8(Y, X, Z, r);\n\t}\n\t/* 10: B' <-- X */\n\tfor (k = 0; k < 32 * r; k++)\n\t\tle32enc(&B[4 * k], X[k]);\n}\n\n/**\n * escrypt_kdf(local, passwd, passwdlen, salt, saltlen,\n *     N, r, p, buf, buflen):\n * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,\n * p, buflen) and write the result into buf.  The parameters r, p, and buflen\n * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N\n * must be a power of 2 greater than 1.\n *\n * Return 0 on success; or -1 on error.\n */\nint\nescrypt_kdf_nosse(escrypt_local_t * local,\n    const uint8_t * passwd, size_t passwdlen,\n    const uint8_t * salt, size_t saltlen,\n    uint64_t N, uint32_t _r, uint32_t _p,\n    uint8_t * buf, size_t buflen)\n{\n\tsize_t B_size, V_size, XY_size, need;\n\tuint8_t * B;\n\tuint32_t * V, * XY;\n    size_t r = _r, p = _p;\n\tuint32_t i;\n\n\t/* Sanity-check parameters. */\n#if SIZE_MAX > UINT32_MAX\n\tif (buflen > (((uint64_t)(1) << 32) - 1) * 32) {\n\t\terrno = EFBIG;\n\t\treturn -1;\n\t}\n#endif\n\tif ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {\n\t\terrno = EFBIG;\n\t\treturn -1;\n\t}\n\tif (((N & (N - 1)) != 0) || (N < 2)) {\n\t\terrno = EINVAL;\n\t\treturn -1;\n\t}\n\tif (r == 0 || p == 0) {\n\t\terrno = EINVAL;\n\t\treturn -1;\n\t}\n\tif ((r > SIZE_MAX / 128 / p) ||\n#if SIZE_MAX / 256 <= UINT32_MAX\n\t    (r > SIZE_MAX / 256) ||\n#endif\n\t    (N > SIZE_MAX / 128 / r)) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\n\t/* Allocate memory. */\n\tB_size = (size_t)128 * r * p;\n\tV_size = (size_t)128 * r * N;\n\tneed = B_size + V_size;\n\tif (need < V_size) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\tXY_size = (size_t)256 * r + 64;\n\tneed += XY_size;\n\tif (need < XY_size) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\tif (local->size < need) {\n\t\tif (free_region(local))\n\t\t\treturn -1;\n\t\tif (!alloc_region(local, need))\n\t\t\treturn -1;\n\t}\n\tB = (uint8_t *)local->aligned;\n\tV = (uint32_t *)((uint8_t *)B + B_size);\n\tXY = (uint32_t *)((uint8_t *)V + V_size);\n\n\t/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */\n\tPBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size);\n\n\t/* 2: for i = 0 to p - 1 do */\n\tfor (i = 0; i < p; i++) {\n\t\t/* 3: B_i <-- MF(B_i, N) */\n\t\tsmix(&B[(size_t)128 * i * r], r, N, V, XY);\n\t}\n\n\t/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */\n\tPBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen);\n\n\t/* Success! */\n\treturn 0;\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt",
    "content": "This folder is only meant for use with nacl, i.e. when sodium is unavailable.\n\n\nThe files in this folder were mostly copied from\nhttps://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/crypto_pwhash/scryptsalsa208sha256,\nwith #ifdef VANILLA_NACL added around each of them as required for this module.\n\nexport.h, utils.h, and runtime.h were copied from\nhttps://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/include/sodium.\nutils.h was significantly truncated.\n\nutils.c and runtime.c were copied from \nhttps://github.com/jedisct1/libsodium/blob/0.7.0/src/libsodium/sodium.\nutils.c was also significantly truncated.\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2005,2007,2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/types.h>\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <crypto_hash_sha256.h>\n#include <crypto_auth_hmacsha256.h>\n\n#include \"pbkdf2-sha256.h\"\n#include \"sysendian.h\"\n#include \"utils.h\"\n\n/**\n * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):\n * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and\n * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).\n */\nvoid\nPBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,\n              size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)\n{\n        uint8_t         key[32] = {0};\n        size_t          i;\n        uint8_t         salt_and_ivec[saltlen + 4];\n        uint8_t         U[32];\n        uint8_t         T[32];\n        uint64_t        j;\n        int             k;\n        size_t          clen;\n\n    if (passwdlen > 32) {\n        /* For some reason libsodium allows 64byte keys meaning keys \n         * between 32byte and 64bytes are not compatible with libsodium. \n           toxencryptsave should only give 32byte passwds so this isn't an issue here.*/\n        crypto_hash_sha256(key, passwd, passwdlen);\n    } else {\n        memcpy(key, passwd, passwdlen);\n    }\n\n    memcpy(salt_and_ivec, salt, saltlen);\n\n        for (i = 0; i * 32 < dkLen; i++) {\n                be32enc(salt_and_ivec + saltlen, (uint32_t)(i + 1));\n                crypto_auth_hmacsha256(U, salt_and_ivec, sizeof(salt_and_ivec), key);\n\n                memcpy(T, U, 32);\n\n                for (j = 2; j <= c; j++) {\n                        crypto_auth_hmacsha256(U, U, 32, key);\n\n                        for (k = 0; k < 32; k++) {\n                                T[k] ^= U[k];\n            }\n                }\n\n                clen = dkLen - i * 32;\n                if (clen > 32) {\n                        clen = 32;\n        }\n                memcpy(&buf[i * 32], T, clen);\n        }\n    sodium_memzero((void *) key, sizeof(key));\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2005,2007,2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n */\n\n#ifndef _SHA256_H_\n#define _SHA256_H_\n\n#include <sys/types.h>\n\n#include <stdint.h>\n\n#include \"crypto_auth_hmacsha256.h\"\n\n/**\n * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):\n * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and\n * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).\n */\nvoid PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,\n                   uint64_t, uint8_t *, size_t);\n\n#endif /* !_SHA256_H_ */\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#include <errno.h>\n#include <limits.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <string.h>\n//#include <stdio.h>\n\n#include \"crypto_pwhash_scryptsalsa208sha256.h\"\n#include \"crypto_scrypt.h\"\n#include \"randombytes.h\"\n#include \"utils.h\"\n\n#define SETTING_SIZE(saltbytes) \\\n    (sizeof \"$7$\" - 1U) + \\\n    (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + BYTES2CHARS(saltbytes)\n\nstatic int\npickparams(unsigned long long opslimit, const size_t memlimit,\n           uint32_t * const N_log2, uint32_t * const p, uint32_t * const r)\n{\n    unsigned long long maxN;\n    unsigned long long maxrp;\n\n    if (opslimit < 32768) {\n        opslimit = 32768;\n    }\n    *r = 8;\n    if (opslimit < memlimit / 32) {\n        *p = 1;\n        maxN = opslimit / (*r * 4);\n        for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) {\n            if ((uint64_t)(1) << *N_log2 > maxN / 2) {\n                break;\n            }\n        }\n    } else {\n        maxN = memlimit / (*r * 128);\n        for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) {\n            if ((uint64_t) (1) << *N_log2 > maxN / 2) {\n                break;\n            }\n        }\n        maxrp = (opslimit / 4) / ((uint64_t) (1) << *N_log2);\n        if (maxrp > 0x3fffffff) {\n            maxrp = 0x3fffffff;\n        }\n        *p = (uint32_t) (maxrp) / *r;\n    }\n    return 0;\n}\n\nsize_t\ncrypto_pwhash_scryptsalsa208sha256_saltbytes(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_SALTBYTES;\n}\n\nsize_t\ncrypto_pwhash_scryptsalsa208sha256_strbytes(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_STRBYTES;\n}\n\nconst char *\ncrypto_pwhash_scryptsalsa208sha256_strprefix(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_STRPREFIX;\n}\n\nsize_t\ncrypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE;\n}\n\nsize_t\ncrypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE;\n}\n\nsize_t\ncrypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE;\n}\n\nsize_t\ncrypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void)\n{\n    return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE;\n}\n\nint\ncrypto_pwhash_scryptsalsa208sha256(unsigned char * const out,\n                                    unsigned long long outlen,\n                                    const char * const passwd,\n                                    unsigned long long passwdlen,\n                                    const unsigned char * const salt,\n                                    unsigned long long opslimit,\n                                    size_t memlimit)\n{\n    //fprintf(stderr, \"Doing that dirty thang!!!!\\n\");\n    uint32_t N_log2;\n    uint32_t p;\n    uint32_t r;\n\n    memset(out, 0, outlen);\n    if (passwdlen > SIZE_MAX || outlen > SIZE_MAX) {\n        errno = EFBIG;\n        return -1;\n    }\n    if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {\n        errno = EINVAL;\n        return -1;\n    }\n    return crypto_pwhash_scryptsalsa208sha256_ll((const uint8_t *) passwd,\n                                                 (size_t) passwdlen,\n                                                 (const uint8_t *) salt,\n                                                 crypto_pwhash_scryptsalsa208sha256_SALTBYTES,\n                                                 (uint64_t) (1) << N_log2, r, p,\n                                                 out, (size_t) outlen);\n}\n\nint\ncrypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES],\n                                        const char * const passwd,\n                                        unsigned long long passwdlen,\n                                        unsigned long long opslimit,\n                                        size_t memlimit)\n{\n    uint8_t         salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES];\n    char            setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U];\n    escrypt_local_t escrypt_local;\n    uint32_t        N_log2;\n    uint32_t        p;\n    uint32_t        r;\n\n    memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES);\n    if (passwdlen > SIZE_MAX) {\n        errno = EFBIG;\n        return -1;\n    }\n    if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) {\n        errno = EINVAL;\n        return -1;\n    }\n    randombytes(salt, sizeof salt);\n    if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt,\n                          (uint8_t *) setting, sizeof setting) == NULL) {\n        errno = EINVAL;\n        return -1;\n    }\n    if (escrypt_init_local(&escrypt_local) != 0) {\n        return -1;\n    }\n    if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen,\n                  (const uint8_t *) setting, (uint8_t *) out,\n                  crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) {\n        escrypt_free_local(&escrypt_local);\n        errno = EINVAL;\n        return -1;\n    }\n    escrypt_free_local(&escrypt_local);\n\n    (void) sizeof\n        (int[SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES)\n            == crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES ? 1 : -1]);\n    (void) sizeof\n        (int[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U +\n             crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U\n             == crypto_pwhash_scryptsalsa208sha256_STRBYTES ? 1 : -1]);\n\n    return 0;\n}\n\nint\ncrypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES],\n                                               const char * const passwd,\n                                               unsigned long long passwdlen)\n{\n    char            wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES];\n    escrypt_local_t escrypt_local;\n    int             ret = -1;\n\n    if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) !=\n        &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) {\n        return -1;\n    }\n    if (escrypt_init_local(&escrypt_local) != 0) {\n        return -1;\n    }\n    if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen,\n                  (const uint8_t *) str, (uint8_t *) wanted,\n                  sizeof wanted) == NULL) {\n        escrypt_free_local(&escrypt_local);\n        return -1;\n    }\n    escrypt_free_local(&escrypt_local);\n    ret = sodium_memcmp(wanted, str, sizeof wanted);\n    sodium_memzero(wanted, sizeof wanted);\n\n    return ret;\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifdef HAVE_ANDROID_GETCPUFEATURES\n# include <cpu-features.h>\n#endif\n\n#include \"runtime.h\"\n\ntypedef struct CPUFeatures_ {\n    int initialized;\n    int has_neon;\n    int has_sse2;\n    int has_sse3;\n} CPUFeatures;\n\nstatic CPUFeatures _cpu_features;\n\n#define CPUID_SSE2     0x04000000\n#define CPUIDECX_SSE3  0x00000001\n\nstatic int\n_sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features)\n{\n#ifndef __arm__\n    cpu_features->has_neon = 0;\n    return -1;\n#else\n# ifdef __APPLE__\n#  ifdef __ARM_NEON__\n    cpu_features->has_neon = 1;\n#  else\n    cpu_features->has_neon = 0;\n#  endif\n# elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON)\n    cpu_features->has_neon =\n        (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0;\n# else\n    cpu_features->has_neon = 0;\n# endif\n    return 0;\n#endif\n}\n\nstatic void\n_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type)\n{\n#ifdef _MSC_VER\n    __cpuidex((int *) cpu_info, cpu_info_type, 0);\n#elif defined(HAVE_CPUID)\n    cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;\n# ifdef __i386__\n    __asm__ __volatile__ (\"pushfl; pushfl; \"\n                          \"popl %0; \"\n                          \"movl %0, %1; xorl %2, %0; \"\n                          \"pushl %0; \"\n                          \"popfl; pushfl; popl %0; popfl\" :\n                          \"=&r\" (cpu_info[0]), \"=&r\" (cpu_info[1]) :\n                          \"i\" (0x200000));\n    if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) {\n        return;\n    }\n# endif\n# ifdef __i386__\n    __asm__ __volatile__ (\"xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1\" :\n                          \"=a\" (cpu_info[0]), \"=&r\" (cpu_info[1]),\n                          \"=c\" (cpu_info[2]), \"=d\" (cpu_info[3]) :\n                          \"0\" (cpu_info_type), \"2\" (0U));\n# elif defined(__x86_64__)\n    __asm__ __volatile__ (\"xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1\" :\n                          \"=a\" (cpu_info[0]), \"=&r\" (cpu_info[1]),\n                          \"=c\" (cpu_info[2]), \"=d\" (cpu_info[3]) :\n                          \"0\" (cpu_info_type), \"2\" (0U));\n# else\n    __asm__ __volatile__ (\"cpuid\" :\n                          \"=a\" (cpu_info[0]), \"=b\" (cpu_info[1]),\n                          \"=c\" (cpu_info[2]), \"=d\" (cpu_info[3]) :\n                          \"0\" (cpu_info_type), \"2\" (0U));\n# endif\n#else\n    cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;\n#endif\n}\n\nstatic int\n_sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features)\n{\n    unsigned int cpu_info[4];\n    unsigned int id;\n\n    _cpuid(cpu_info, 0x0);\n    if ((id = cpu_info[0]) == 0U) {\n        return -1;\n    }\n    _cpuid(cpu_info, 0x00000001);\n#ifndef HAVE_EMMINTRIN_H\n    cpu_features->has_sse2 = 0;\n#else\n    cpu_features->has_sse2 = ((cpu_info[3] & CPUID_SSE2) != 0x0);\n#endif\n\n#ifndef HAVE_PMMINTRIN_H\n    cpu_features->has_sse3 = 0;\n#else\n    cpu_features->has_sse3 = ((cpu_info[2] & CPUIDECX_SSE3) != 0x0);\n#endif\n\n    return 0;\n}\n\nint\nsodium_runtime_get_cpu_features(void)\n{\n    int ret = -1;\n\n    ret &= _sodium_runtime_arm_cpu_features(&_cpu_features);\n    ret &= _sodium_runtime_intel_cpu_features(&_cpu_features);\n    _cpu_features.initialized = 1;\n\n    return ret;\n}\n\nint\nsodium_runtime_has_neon(void) {\n    return _cpu_features.has_neon;\n}\n\nint\nsodium_runtime_has_sse2(void) {\n    return _cpu_features.has_sse2;\n}\n\nint\nsodium_runtime_has_sse3(void) {\n    return _cpu_features.has_sse3;\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifndef __SODIUM_RUNTIME_H__\n#define __SODIUM_RUNTIME_H__ 1\n\n#include \"export.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSODIUM_EXPORT\nint sodium_runtime_get_cpu_features(void);\n\nSODIUM_EXPORT\nint sodium_runtime_has_neon(void);\n\nSODIUM_EXPORT\nint sodium_runtime_has_sse2(void);\n\nSODIUM_EXPORT\nint sodium_runtime_has_sse3(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2013 Alexander Peslyak\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#ifdef HAVE_SYS_MMAN_H\n# include <sys/mman.h>\n#endif\n#include <errno.h>\n#include <stdlib.h>\n\n#include \"crypto_scrypt.h\"\n#include \"runtime.h\"\n\n#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)\n# define MAP_ANON MAP_ANONYMOUS\n#endif\n\nvoid *\nalloc_region(escrypt_region_t * region, size_t size)\n{\n\tuint8_t * base, * aligned;\n#ifdef MAP_ANON\n\tif ((base = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE,\n#ifdef MAP_NOCORE\n\t    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,\n#else\n\t    MAP_ANON | MAP_PRIVATE,\n#endif\n\t    -1, 0)) == MAP_FAILED)\n\t\tbase = NULL;\n\taligned = base;\n#elif defined(HAVE_POSIX_MEMALIGN)\n\tif ((errno = posix_memalign((void **) &base, 64, size)) != 0)\n\t\tbase = NULL;\n\taligned = base;\n#else\n\tbase = aligned = NULL;\n\tif (size + 63 < size)\n\t\terrno = ENOMEM;\n\telse if ((base = (uint8_t *) malloc(size + 63)) != NULL) {\n\t\taligned = base + 63;\n\t\taligned -= (uintptr_t)aligned & 63;\n\t}\n#endif\n\tregion->base = base;\n\tregion->aligned = aligned;\n\tregion->size = base ? size : 0;\n\treturn aligned;\n}\n\nstatic inline void\ninit_region(escrypt_region_t * region)\n{\n\tregion->base = region->aligned = NULL;\n\tregion->size = 0;\n}\n\nint\nfree_region(escrypt_region_t * region)\n{\n\tif (region->base) {\n#ifdef MAP_ANON\n\t\tif (munmap(region->base, region->size))\n\t\t\treturn -1;\n#else\n\t\tfree(region->base);\n#endif\n\t}\n\tinit_region(region);\n\treturn 0;\n}\n\nint\nescrypt_init_local(escrypt_local_t * local)\n{\n\tinit_region(local);\n\treturn 0;\n}\n\nint\nescrypt_free_local(escrypt_local_t * local)\n{\n\treturn free_region(local);\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n/*-\n * Copyright 2009 Colin Percival\n * Copyright 2012,2013 Alexander Peslyak\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * This file was originally written by Colin Percival as part of the Tarsnap\n * online backup system.\n */\n\n#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER)\n#if __GNUC__\n# pragma GCC target(\"sse2\")\n#endif\n#include <emmintrin.h>\n#if defined(__XOP__) && defined(DISABLED)\n# include <x86intrin.h>\n#endif\n\n#include <errno.h>\n#include <limits.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"../pbkdf2-sha256.h\"\n#include \"../sysendian.h\"\n#include \"../crypto_scrypt.h\"\n\n#if defined(__XOP__) && defined(DISABLED)\n#define ARX(out, in1, in2, s) \\\n\tout = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s));\n#else\n#define ARX(out, in1, in2, s) \\\n\t{ \\\n\t\t__m128i T = _mm_add_epi32(in1, in2); \\\n\t\tout = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \\\n\t\tout = _mm_xor_si128(out, _mm_srli_epi32(T, 32-s)); \\\n\t}\n#endif\n\n#define SALSA20_2ROUNDS \\\n\t/* Operate on \"columns\". */ \\\n\tARX(X1, X0, X3, 7) \\\n\tARX(X2, X1, X0, 9) \\\n\tARX(X3, X2, X1, 13) \\\n\tARX(X0, X3, X2, 18) \\\n\\\n\t/* Rearrange data. */ \\\n\tX1 = _mm_shuffle_epi32(X1, 0x93); \\\n\tX2 = _mm_shuffle_epi32(X2, 0x4E); \\\n\tX3 = _mm_shuffle_epi32(X3, 0x39); \\\n\\\n\t/* Operate on \"rows\". */ \\\n\tARX(X3, X0, X1, 7) \\\n\tARX(X2, X3, X0, 9) \\\n\tARX(X1, X2, X3, 13) \\\n\tARX(X0, X1, X2, 18) \\\n\\\n\t/* Rearrange data. */ \\\n\tX1 = _mm_shuffle_epi32(X1, 0x39); \\\n\tX2 = _mm_shuffle_epi32(X2, 0x4E); \\\n\tX3 = _mm_shuffle_epi32(X3, 0x93);\n\n/**\n * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3).\n */\n#define SALSA20_8_XOR(in, out) \\\n\t{ \\\n\t\t__m128i Y0 = X0 = _mm_xor_si128(X0, (in)[0]); \\\n\t\t__m128i Y1 = X1 = _mm_xor_si128(X1, (in)[1]); \\\n\t\t__m128i Y2 = X2 = _mm_xor_si128(X2, (in)[2]); \\\n\t\t__m128i Y3 = X3 = _mm_xor_si128(X3, (in)[3]); \\\n\t\tSALSA20_2ROUNDS \\\n\t\tSALSA20_2ROUNDS \\\n\t\tSALSA20_2ROUNDS \\\n\t\tSALSA20_2ROUNDS \\\n\t\t(out)[0] = X0 = _mm_add_epi32(X0, Y0); \\\n\t\t(out)[1] = X1 = _mm_add_epi32(X1, Y1); \\\n\t\t(out)[2] = X2 = _mm_add_epi32(X2, Y2); \\\n\t\t(out)[3] = X3 = _mm_add_epi32(X3, Y3); \\\n\t}\n\n/**\n * blockmix_salsa8(Bin, Bout, r):\n * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r\n * bytes in length; the output Bout must also be the same size.\n */\nstatic inline void\nblockmix_salsa8(const __m128i * Bin, __m128i * Bout, size_t r)\n{\n\t__m128i X0, X1, X2, X3;\n\tsize_t i;\n\n\t/* 1: X <-- B_{2r - 1} */\n\tX0 = Bin[8 * r - 4];\n\tX1 = Bin[8 * r - 3];\n\tX2 = Bin[8 * r - 2];\n\tX3 = Bin[8 * r - 1];\n\n\t/* 3: X <-- H(X \\xor B_i) */\n\t/* 4: Y_i <-- X */\n\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\tSALSA20_8_XOR(Bin, Bout)\n\n\t/* 2: for i = 0 to 2r - 1 do */\n\tr--;\n\tfor (i = 0; i < r;) {\n\t\t/* 3: X <-- H(X \\xor B_i) */\n\t\t/* 4: Y_i <-- X */\n\t\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\t\tSALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4])\n\n\t\ti++;\n\n\t\t/* 3: X <-- H(X \\xor B_i) */\n\t\t/* 4: Y_i <-- X */\n\t\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\t\tSALSA20_8_XOR(&Bin[i * 8], &Bout[i * 4])\n\t}\n\n\t/* 3: X <-- H(X \\xor B_i) */\n\t/* 4: Y_i <-- X */\n\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\tSALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4])\n}\n\n#define XOR4(in) \\\n\tX0 = _mm_xor_si128(X0, (in)[0]); \\\n\tX1 = _mm_xor_si128(X1, (in)[1]); \\\n\tX2 = _mm_xor_si128(X2, (in)[2]); \\\n\tX3 = _mm_xor_si128(X3, (in)[3]);\n\n#define XOR4_2(in1, in2) \\\n\tX0 = _mm_xor_si128((in1)[0], (in2)[0]); \\\n\tX1 = _mm_xor_si128((in1)[1], (in2)[1]); \\\n\tX2 = _mm_xor_si128((in1)[2], (in2)[2]); \\\n\tX3 = _mm_xor_si128((in1)[3], (in2)[3]);\n\nstatic inline uint32_t\nblockmix_salsa8_xor(const __m128i * Bin1, const __m128i * Bin2, __m128i * Bout,\n    size_t r)\n{\n\t__m128i X0, X1, X2, X3;\n\tsize_t i;\n\n\t/* 1: X <-- B_{2r - 1} */\n\tXOR4_2(&Bin1[8 * r - 4], &Bin2[8 * r - 4])\n\n\t/* 3: X <-- H(X \\xor B_i) */\n\t/* 4: Y_i <-- X */\n\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\tXOR4(Bin1)\n\tSALSA20_8_XOR(Bin2, Bout)\n\n\t/* 2: for i = 0 to 2r - 1 do */\n\tr--;\n\tfor (i = 0; i < r;) {\n\t\t/* 3: X <-- H(X \\xor B_i) */\n\t\t/* 4: Y_i <-- X */\n\t\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\t\tXOR4(&Bin1[i * 8 + 4])\n\t\tSALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4])\n\n\t\ti++;\n\n\t\t/* 3: X <-- H(X \\xor B_i) */\n\t\t/* 4: Y_i <-- X */\n\t\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\t\tXOR4(&Bin1[i * 8])\n\t\tSALSA20_8_XOR(&Bin2[i * 8], &Bout[i * 4])\n\t}\n\n\t/* 3: X <-- H(X \\xor B_i) */\n\t/* 4: Y_i <-- X */\n\t/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */\n\tXOR4(&Bin1[i * 8 + 4])\n\tSALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4])\n\n\treturn _mm_cvtsi128_si32(X0);\n}\n\n#undef ARX\n#undef SALSA20_2ROUNDS\n#undef SALSA20_8_XOR\n#undef XOR4\n#undef XOR4_2\n\n/**\n * integerify(B, r):\n * Return the result of parsing B_{2r-1} as a little-endian integer.\n */\nstatic inline uint32_t\nintegerify(const void * B, size_t r)\n{\n\treturn *(const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64);\n}\n\n/**\n * smix(B, r, N, V, XY):\n * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;\n * the temporary storage V must be 128rN bytes in length; the temporary\n * storage XY must be 256r + 64 bytes in length.  The value N must be a\n * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a\n * multiple of 64 bytes.\n */\nstatic void\nsmix(uint8_t * B, size_t r, uint32_t N, void * V, void * XY)\n{\n\tsize_t s = 128 * r;\n\t__m128i * X = (__m128i *) V, * Y;\n\tuint32_t * X32 = (uint32_t *) V;\n\tuint32_t i, j;\n\tsize_t k;\n\n\t/* 1: X <-- B */\n\t/* 3: V_i <-- X */\n\tfor (k = 0; k < 2 * r; k++) {\n\t\tfor (i = 0; i < 16; i++) {\n\t\t\tX32[k * 16 + i] =\n\t\t\t    le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]);\n\t\t}\n\t}\n\n\t/* 2: for i = 0 to N - 1 do */\n\tfor (i = 1; i < N - 1; i += 2) {\n\t\t/* 4: X <-- H(X) */\n\t\t/* 3: V_i <-- X */\n\t\tY = (__m128i *)((uintptr_t)(V) + i * s);\n\t\tblockmix_salsa8(X, Y, r);\n\n\t\t/* 4: X <-- H(X) */\n\t\t/* 3: V_i <-- X */\n\t\tX = (__m128i *)((uintptr_t)(V) + (i + 1) * s);\n\t\tblockmix_salsa8(Y, X, r);\n\t}\n\n\t/* 4: X <-- H(X) */\n\t/* 3: V_i <-- X */\n\tY = (__m128i *)((uintptr_t)(V) + i * s);\n\tblockmix_salsa8(X, Y, r);\n\n\t/* 4: X <-- H(X) */\n\t/* 3: V_i <-- X */\n\tX = (__m128i *) XY;\n\tblockmix_salsa8(Y, X, r);\n\n\tX32 = (uint32_t *) XY;\n\tY = (__m128i *)((uintptr_t)(XY) + s);\n\n\t/* 7: j <-- Integerify(X) mod N */\n\tj = integerify(X, r) & (N - 1);\n\n\t/* 6: for i = 0 to N - 1 do */\n\tfor (i = 0; i < N; i += 2) {\n\t\t__m128i * V_j = (__m128i *)((uintptr_t)(V) + j * s);\n\n\t\t/* 8: X <-- H(X \\xor V_j) */\n\t\t/* 7: j <-- Integerify(X) mod N */\n\t\tj = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1);\n\t\tV_j = (__m128i *)((uintptr_t)(V) + j * s);\n\n\t\t/* 8: X <-- H(X \\xor V_j) */\n\t\t/* 7: j <-- Integerify(X) mod N */\n\t\tj = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1);\n\t}\n\n\t/* 10: B' <-- X */\n\tfor (k = 0; k < 2 * r; k++) {\n\t\tfor (i = 0; i < 16; i++) {\n\t\t\tle32enc(&B[(k * 16 + (i * 5 % 16)) * 4],\n\t\t\t    X32[k * 16 + i]);\n\t\t}\n\t}\n}\n\n/**\n * escrypt_kdf(local, passwd, passwdlen, salt, saltlen,\n *     N, r, p, buf, buflen):\n * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,\n * p, buflen) and write the result into buf.  The parameters r, p, and buflen\n * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N\n * must be a power of 2 greater than 1.\n *\n * Return 0 on success; or -1 on error.\n */\nint\nescrypt_kdf_sse(escrypt_local_t * local,\n    const uint8_t * passwd, size_t passwdlen,\n    const uint8_t * salt, size_t saltlen,\n    uint64_t N, uint32_t _r, uint32_t _p,\n    uint8_t * buf, size_t buflen)\n{\n\tsize_t B_size, V_size, XY_size, need;\n\tuint8_t * B;\n\tuint32_t * V, * XY;\n    size_t r = _r, p = _p;\n\tuint32_t i;\n\n\t/* Sanity-check parameters. */\n#if SIZE_MAX > UINT32_MAX\n\tif (buflen > (((uint64_t)(1) << 32) - 1) * 32) {\n\t\terrno = EFBIG;\n\t\treturn -1;\n\t}\n#endif\n\tif ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {\n\t\terrno = EFBIG;\n\t\treturn -1;\n\t}\n\tif (N > UINT32_MAX) {\n\t\terrno = EFBIG;\n\t\treturn -1;\n\t}\n\tif (((N & (N - 1)) != 0) || (N < 2)) {\n\t\terrno = EINVAL;\n\t\treturn -1;\n\t}\n\tif (r == 0 || p == 0) {\n\t\terrno = EINVAL;\n\t\treturn -1;\n\t}\n\tif ((r > SIZE_MAX / 128 / p) ||\n#if SIZE_MAX / 256 <= UINT32_MAX\n\t    (r > SIZE_MAX / 256) ||\n#endif\n\t    (N > SIZE_MAX / 128 / r)) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\n\t/* Allocate memory. */\n\tB_size = (size_t)128 * r * p;\n\tV_size = (size_t)128 * r * N;\n\tneed = B_size + V_size;\n\tif (need < V_size) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\tXY_size = (size_t)256 * r + 64;\n\tneed += XY_size;\n\tif (need < XY_size) {\n\t\terrno = ENOMEM;\n\t\treturn -1;\n\t}\n\tif (local->size < need) {\n\t\tif (free_region(local))\n\t\t\treturn -1;\n\t\tif (!alloc_region(local, need))\n\t\t\treturn -1;\n\t}\n\tB = (uint8_t *)local->aligned;\n\tV = (uint32_t *)((uint8_t *)B + B_size);\n\tXY = (uint32_t *)((uint8_t *)V + V_size);\n\n\t/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */\n\tPBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size);\n\n\t/* 2: for i = 0 to p - 1 do */\n\tfor (i = 0; i < p; i++) {\n\t\t/* 3: B_i <-- MF(B_i, N) */\n\t\tsmix(&B[(size_t)128 * i * r], r, N, V, XY);\n\t}\n\n\t/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */\n\tPBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen);\n\n\t/* Success! */\n\treturn 0;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifndef _SYSENDIAN_H_\n#define _SYSENDIAN_H_\n\n#include <stdint.h>\n\n/* Avoid namespace collisions with BSD <sys/endian.h>. */\n#define be16dec scrypt_be16dec\n#define be16enc scrypt_be16enc\n#define be32dec scrypt_be32dec\n#define be32enc scrypt_be32enc\n#define be64dec scrypt_be64dec\n#define be64enc scrypt_be64enc\n#define le16dec scrypt_le16dec\n#define le16enc scrypt_le16enc\n#define le32dec scrypt_le32dec\n#define le32enc scrypt_le32enc\n#define le64dec scrypt_le64dec\n#define le64enc scrypt_le64enc\n\nstatic inline uint16_t\nbe16dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\n\treturn ((uint16_t)(p[1]) + ((uint16_t)(p[0]) << 8));\n}\n\nstatic inline void\nbe16enc(void *pp, uint16_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[1] = x & 0xff;\n\tp[0] = (x >> 8) & 0xff;\n}\n\nstatic inline uint32_t\nbe32dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\n\treturn ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +\n\t    ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));\n}\n\nstatic inline void\nbe32enc(void *pp, uint32_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[3] = x & 0xff;\n\tp[2] = (x >> 8) & 0xff;\n\tp[1] = (x >> 16) & 0xff;\n\tp[0] = (x >> 24) & 0xff;\n}\n\nstatic inline uint64_t\nbe64dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\n\treturn ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) +\n\t    ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) +\n\t    ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) +\n\t    ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56));\n}\n\nstatic inline void\nbe64enc(void *pp, uint64_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[7] = x & 0xff;\n\tp[6] = (x >> 8) & 0xff;\n\tp[5] = (x >> 16) & 0xff;\n\tp[4] = (x >> 24) & 0xff;\n\tp[3] = (x >> 32) & 0xff;\n\tp[2] = (x >> 40) & 0xff;\n\tp[1] = (x >> 48) & 0xff;\n\tp[0] = (x >> 56) & 0xff;\n}\n\nstatic inline uint16_t\nle16dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\n\treturn ((uint16_t)(p[0]) + ((uint16_t)(p[1]) << 8));\n}\n\nstatic inline void\nle16enc(void *pp, uint16_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[0] = x & 0xff;\n\tp[1] = (x >> 8) & 0xff;\n}\n\nstatic inline uint32_t\nle32dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\n\treturn ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +\n\t    ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));\n}\n\nstatic inline void\nle32enc(void *pp, uint32_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[0] = x & 0xff;\n\tp[1] = (x >> 8) & 0xff;\n\tp[2] = (x >> 16) & 0xff;\n\tp[3] = (x >> 24) & 0xff;\n}\n\nstatic inline uint64_t\nle64dec(const void *pp)\n{\n\tconst uint8_t *p = (uint8_t const *)pp;\n\n\treturn ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) +\n\t    ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) +\n\t    ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) +\n\t    ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56));\n}\n\nstatic inline void\nle64enc(void *pp, uint64_t x)\n{\n\tuint8_t * p = (uint8_t *)pp;\n\n\tp[0] = x & 0xff;\n\tp[1] = (x >> 8) & 0xff;\n\tp[2] = (x >> 16) & 0xff;\n\tp[3] = (x >> 24) & 0xff;\n\tp[4] = (x >> 32) & 0xff;\n\tp[5] = (x >> 40) & 0xff;\n\tp[6] = (x >> 48) & 0xff;\n\tp[7] = (x >> 56) & 0xff;\n}\n\n#endif /* !_SYSENDIAN_H_ */\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifndef __STDC_WANT_LIB_EXT1__\n# define __STDC_WANT_LIB_EXT1__ 1\n#endif\n#include <assert.h>\n#include <errno.h>\n#include <limits.h>\n#include <signal.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef HAVE_SYS_MMAN_H\n# include <sys/mman.h>\n#endif\n\n#include \"utils.h\"\n\n#ifdef _WIN32\n# include <windows.h>\n# include <wincrypt.h>\n#else\n# include <unistd.h>\n#endif\n\n#ifdef HAVE_WEAK_SYMBOLS\n__attribute__((weak)) void\n__sodium_dummy_symbol_to_prevent_lto(void * const pnt, const size_t len)\n{\n    (void) pnt;\n    (void) len;\n}\n#endif\n\nvoid\nsodium_memzero(void * const pnt, const size_t len)\n{\n#ifdef _WIN32\n    SecureZeroMemory(pnt, len);\n#elif defined(HAVE_MEMSET_S)\n    if (memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) {\n        abort();\n    }\n#elif defined(HAVE_EXPLICIT_BZERO)\n    explicit_bzero(pnt, len);\n#elif HAVE_WEAK_SYMBOLS\n    memset(pnt, 0, len);\n    __sodium_dummy_symbol_to_prevent_lto(pnt, len);\n#else\n    volatile unsigned char *pnt_ = (volatile unsigned char *) pnt;\n    size_t                     i = (size_t) 0U;\n\n    while (i < len) {\n        pnt_[i++] = 0U;\n    }\n#endif\n}\n\nint\nsodium_memcmp(const void * const b1_, const void * const b2_, size_t len)\n{\n    const unsigned char *b1 = (const unsigned char *) b1_;\n    const unsigned char *b2 = (const unsigned char *) b2_;\n    size_t               i;\n    unsigned char        d = (unsigned char) 0U;\n\n    for (i = 0U; i < len; i++) {\n        d |= b1[i] ^ b2[i];\n    }\n    return (int) ((1 & ((d - 1) >> 8)) - 1);\n}\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h",
    "content": "#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n#ifdef  VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */\n\n#ifndef __SODIUM_UTILS_H__\n#define __SODIUM_UTILS_H__\n\n#include <stddef.h>\n\n#include \"export.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L\n# define _SODIUM_C99(X)\n#else\n# define _SODIUM_C99(X) X\n#endif\n\nSODIUM_EXPORT\nvoid sodium_memzero(void * const pnt, const size_t len);\n\n/* WARNING: sodium_memcmp() must be used to verify if two secret keys\n * are equal, in constant time.\n * It returns 0 if the keys are equal, and -1 if they differ.\n * This function is not designed for lexicographical comparisons.\n */\nSODIUM_EXPORT\nint sodium_memcmp(const void * const b1_, const void * const b2_, size_t len);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "toxencryptsave/defines.h",
    "content": "#define TOX_ENC_SAVE_MAGIC_NUMBER \"toxEsave\"\n#define TOX_ENC_SAVE_MAGIC_LENGTH 8\n"
  },
  {
    "path": "toxencryptsave/toxencryptsave.c",
    "content": "/* toxencryptsave.c\n *\n * The Tox encrypted save functions.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"toxencryptsave.h\"\n#include \"defines.h\"\n#include \"../toxcore/crypto_core.h\"\n#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}}\n\n#ifdef VANILLA_NACL\n#include \"crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h\"\n#include <crypto_hash_sha256.h>\n#endif\n\n#if TOX_PASS_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES\n#error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES\n#endif\n\n#if TOX_PASS_KEY_LENGTH != crypto_box_KEYBYTES\n#error TOX_PASS_KEY_LENGTH is assumed to be equal to crypto_box_KEYBYTES\n#endif\n\n#if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH)\n#error TOX_PASS_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH)\n#endif\n\nuint32_t toxes_version_major(void)\n{\n    return TOXES_VERSION_MAJOR;\n}\n\nuint32_t toxes_version_minor(void)\n{\n    return TOXES_VERSION_MINOR;\n}\n\nuint32_t toxes_version_patch(void)\n{\n    return TOXES_VERSION_PATCH;\n}\n\nbool toxes_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch)\n{\n  return (TOXES_VERSION_MAJOR == major && /* Force the major version */\n            (TOXES_VERSION_MINOR > minor || /* Current minor version must be newer than requested  -- or -- */\n                (TOXES_VERSION_MINOR == minor && TOXES_VERSION_PATCH >= patch) /* the patch must be the same or newer */\n            )\n         );\n}\n\n/* Clients should consider alerting their users that, unlike plain data, if even one bit\n * becomes corrupted, the data will be entirely unrecoverable.\n * Ditto if they forget their password, there is no way to recover the data.\n */\n\n/* This retrieves the salt used to encrypt the given data, which can then be passed to\n * derive_key_with_salt to produce the same key as was previously used. Any encrpyted\n * data with this module can be used as input.\n *\n * returns true if magic number matches\n * success does not say anything about the validity of the data, only that data of\n * the appropriate size was copied\n */\nbool tox_get_salt(const uint8_t *data, uint8_t *salt)\n{\n    if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0)\n        return 0;\n\n    data += TOX_ENC_SAVE_MAGIC_LENGTH;\n    memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES);\n    return 1;\n}\n\n/* Generates a secret symmetric key from the given passphrase. out_key must be at least\n * TOX_PASS_KEY_LENGTH bytes long.\n * Be sure to not compromise the key! Only keep it in memory, do not write to disk.\n * The password is zeroed after key derivation.\n * The key should only be used with the other functions in this module, as it\n * includes a salt.\n * Note that this function is not deterministic; to derive the same key from a\n * password, you also must know the random salt that was used. See below.\n *\n * returns true on success\n */\nbool tox_derive_key_from_pass(const uint8_t *passphrase, size_t pplength, TOX_PASS_KEY *out_key,\n                              TOX_ERR_KEY_DERIVATION *error)\n{\n    uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];\n    randombytes(salt, sizeof salt);\n    return tox_derive_key_with_salt(passphrase, pplength, salt, out_key, error);\n}\n\n/* Same as above, except with use the given salt for deterministic key derivation.\n * The salt must be TOX_PASS_SALT_LENGTH bytes in length.\n */\nbool tox_derive_key_with_salt(const uint8_t *passphrase, size_t pplength, const uint8_t *salt, TOX_PASS_KEY *out_key,\n                              TOX_ERR_KEY_DERIVATION *error)\n{\n    if (!salt || !out_key || (!passphrase && pplength != 0)) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL);\n        return 0;\n    }\n\n    uint8_t passkey[crypto_hash_sha256_BYTES];\n    crypto_hash_sha256(passkey, passphrase, pplength);\n\n    uint8_t key[crypto_box_KEYBYTES];\n\n    /* Derive a key from the password */\n    /* http://doc.libsodium.org/key_derivation/README.html */\n    /* note that, according to the documentation, a generic pwhash interface will be created\n     * once the pwhash competition (https://password-hashing.net/) is over */\n    if (crypto_pwhash_scryptsalsa208sha256(\n                key, sizeof(key), (char *)passkey, sizeof(passkey), salt,\n                crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */\n                crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) {\n        /* out of memory most likely */\n        SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED);\n        return 0;\n    }\n\n    sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */\n    memcpy(out_key->salt, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES);\n    memcpy(out_key->key, key, crypto_box_KEYBYTES);\n    SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK);\n    return 1;\n}\n\n/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output\n * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long.\n * key must be TOX_PASS_KEY_LENGTH bytes.\n * If you already have a symmetric key from somewhere besides this module, simply\n * call encrypt_data_symmetric in toxcore/crypto_core directly.\n *\n * returns true on success\n */\nbool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const TOX_PASS_KEY *key, uint8_t *out,\n                          TOX_ERR_ENCRYPTION *error)\n{\n    if (data_len == 0 || !data || !key || !out) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL);\n        return 0;\n    }\n\n    /* the output data consists of, in order:\n     * salt, nonce, mac, enc_data\n     * where the mac is automatically prepended by the encrypt()\n     * the salt+nonce is called the prefix\n     * I'm not sure what else I'm supposed to do with the salt and nonce, since we\n     * need them to decrypt the data\n     */\n\n    /* first add the magic number */\n    memcpy(out, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH);\n    out += TOX_ENC_SAVE_MAGIC_LENGTH;\n\n    /* then add the rest prefix */\n    memcpy(out, key->salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES);\n    out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES;\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    random_nonce(nonce);\n    memcpy(out, nonce, crypto_box_NONCEBYTES);\n    out += crypto_box_NONCEBYTES;\n\n    /* now encrypt */\n    if (encrypt_data_symmetric(key->key, nonce, data, data_len, out)\n            != data_len + crypto_box_MACBYTES) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_OK);\n    return 1;\n}\n\n/* Encrypts the given data with the given passphrase. The output array must be\n * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates\n * to tox_derive_key_from_pass and tox_pass_key_encrypt.\n *\n * returns true on success\n */\nbool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passphrase, size_t pplength, uint8_t *out,\n                      TOX_ERR_ENCRYPTION *error)\n{\n    TOX_PASS_KEY key;\n    TOX_ERR_KEY_DERIVATION _error;\n\n    if (!tox_derive_key_from_pass(passphrase, pplength, &key, &_error)) {\n        if (_error == TOX_ERR_KEY_DERIVATION_NULL) {\n            SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL);\n        } else if (_error == TOX_ERR_KEY_DERIVATION_FAILED) {\n            SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED);\n        }\n\n        return 0;\n    }\n\n    return tox_pass_key_encrypt(data, data_len, &key, out, error);\n}\n\n/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by\n * tox_derive_key_from_pass.\n *\n * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH\n *\n * returns true on success\n */\nbool tox_pass_key_decrypt(const uint8_t *data, size_t length, const TOX_PASS_KEY *key, uint8_t *out,\n                          TOX_ERR_DECRYPTION *error)\n{\n    if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);\n        return 0;\n    }\n\n    if (!data || !key || !out) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL);\n        return 0;\n    }\n\n    if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT);\n        return 0;\n    }\n\n    data += TOX_ENC_SAVE_MAGIC_LENGTH;\n    data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // salt only affects key derivation\n\n    size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH;\n\n    uint8_t nonce[crypto_box_NONCEBYTES];\n    memcpy(nonce, data, crypto_box_NONCEBYTES);\n    data += crypto_box_NONCEBYTES;\n\n    /* decrypt the data */\n    if (decrypt_data_symmetric(key->key, nonce, data, decrypt_length + crypto_box_MACBYTES, out)\n            != decrypt_length) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED);\n        return 0;\n    }\n\n    SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK);\n    return 1;\n}\n\n/* Decrypts the given data with the given passphrase. The output array must be\n * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates\n * to tox_pass_key_decrypt.\n *\n * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH\n *\n * returns true on success\n */\nbool tox_pass_decrypt(const uint8_t *data, size_t length, const uint8_t *passphrase, size_t pplength, uint8_t *out,\n                      TOX_ERR_DECRYPTION *error)\n{\n    if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH);\n        return 0;\n    }\n\n    if (!data || !passphrase || !out) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL);\n        return 0;\n    }\n\n    if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) {\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT);\n        return 0;\n    }\n\n    uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];\n    memcpy(salt, data + TOX_ENC_SAVE_MAGIC_LENGTH, crypto_pwhash_scryptsalsa208sha256_SALTBYTES);\n\n    /* derive the key */\n    TOX_PASS_KEY key;\n\n    if (!tox_derive_key_with_salt(passphrase, pplength, salt, &key, NULL)) {\n        /* out of memory most likely */\n        SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED);\n        return 0;\n    }\n\n    return tox_pass_key_decrypt(data, length, &key, out, error);\n}\n\n/* Determines whether or not the given data is encrypted (by checking the magic number)\n */\nbool tox_is_data_encrypted(const uint8_t *data)\n{\n    if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0)\n        return 1;\n    else\n        return 0;\n}\n"
  },
  {
    "path": "toxencryptsave/toxencryptsave.h",
    "content": "/* toxencryptsave.h\n *\n * The Tox encrypted save functions.\n *\n *  Copyright (C) 2013 Tox project All Rights Reserved.\n *\n *  This file is part of Tox.\n *\n *  Tox is free software: you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation, either version 3 of the License, or\n *  (at your option) any later version.\n *\n *  Tox is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License\n *  along with Tox.  If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\n#ifndef TOXENCRYPTSAVE_H\n#define TOXENCRYPTSAVE_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n#include <stddef.h>\n#include <stdbool.h>\n\n#ifndef TOX_DEFINED\n#define TOX_DEFINED\ntypedef struct Tox Tox;\nstruct Tox_Options;\n#endif\n\n#define TOX_PASS_SALT_LENGTH 32\n#define TOX_PASS_KEY_LENGTH 32\n#define TOX_PASS_ENCRYPTION_EXTRA_LENGTH 80\n\n/**\n * ToxEncryptSave.\n */\n#ifndef TOXES_DEFINED\n#define TOXES_DEFINED\n#endif /* TOXES_DEFINED */\n\n\n/*******************************************************************************\n *\n * :: API version\n *\n ******************************************************************************/\n/**\n * The major version number. Incremented when the API or ABI changes in an\n * incompatible way.\n */\n#define TOXES_VERSION_MAJOR               0u\n\n/**\n * The minor version number. Incremented when functionality is added without\n * breaking the API or ABI. Set to 0 when the major version number is\n * incremented.\n */\n#define TOXES_VERSION_MINOR               0u\n\n/**\n * The patch or revision number. Incremented when bugfixes are applied without\n * changing any functionality or API or ABI.\n */\n#define TOXES_VERSION_PATCH               0u\n\n/**\n * A macro to check at preprocessing time whether the client code is compatible\n * with the installed version of ToxAV.\n */\n#define TOXES_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH)        \\\n  (TOXES_VERSION_MAJOR == MAJOR &&                                \\\n   (TOXES_VERSION_MINOR > MINOR ||                                \\\n    (TOXES_VERSION_MINOR == MINOR &&                              \\\n     TOXES_VERSION_PATCH >= PATCH)))\n\n/**\n * A macro to make compilation fail if the client code is not compatible with\n * the installed version of ToxAV.\n */\n#define TOXES_VERSION_REQUIRE(MAJOR, MINOR, PATCH)                \\\n  typedef char toxes_required_version[TOXES_IS_COMPATIBLE(MAJOR, MINOR, PATCH) ? 1 : -1]\n\n/**\n * A convenience macro to call toxES_version_is_compatible with the currently\n * compiling API version.\n */\n#define TOXES_VERSION_IS_ABI_COMPATIBLE()                         \\\n  toxes_version_is_compatible(TOXES_VERSION_MAJOR, TOXES_VERSION_MINOR, TOXES_VERSION_PATCH)\n\n/**\n * Return the major version number of the library. Can be used to display the\n * ToxAV library version or to check whether the client is compatible with the\n * dynamically linked version of ToxAV.\n */\nuint32_t toxes_version_major(void);\n\n/**\n * Return the minor version number of the library.\n */\nuint32_t toxes_version_minor(void);\n\n/**\n * Return the patch number of the library.\n */\nuint32_t toxes_version_patch(void);\n\n/**\n * Return whether the compiled library version is compatible with the passed\n * version numbers.\n */\nbool toxes_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch);\n\n\n\n/* This module is conceptually organized into two parts. The first part are the functions\n * with \"key\" in the name. To use these functions, first derive an encryption key\n * from a password with tox_derive_key_from_pass, and use the returned key to\n * encrypt the data. The second part takes the password itself instead of the key,\n * and then delegates to the first part to derive the key before de/encryption,\n * which can simplify client code; however, key derivation is very expensive\n * compared to the actual encryption, so clients that do a lot of encryption should\n * favor using the first part intead of the second part.\n *\n * The encrypted data is prepended with a magic number, to aid validity checking\n * (no guarantees are made of course). Any data to be decrypted must start with\n * the magic number.\n *\n * Clients should consider alerting their users that, unlike plain data, if even one bit\n * becomes corrupted, the data will be entirely unrecoverable.\n * Ditto if they forget their password, there is no way to recover the data.\n */\n\n/* Since apparently no one actually bothered to learn about the module previously,\n * the recently removed functions tox_encrypted_new and tox_get_encrypted_savedata\n * may be trivially replaced by calls to tox_pass_decrypt -> tox_new or\n * tox_get_savedata -> tox_pass_encrypt as appropriate. The removed functions\n * were never more than 5 line wrappers of the other public API functions anyways.\n * (As has always been, tox_pass_decrypt and tox_pass_encrypt are interchangeable\n *  with tox_pass_key_decrypt and tox_pass_key_encrypt, as the client program requires.)\n */\n\ntypedef enum TOX_ERR_KEY_DERIVATION {\n    TOX_ERR_KEY_DERIVATION_OK,\n    /**\n     * Some input data, or maybe the output pointer, was null.\n     */\n    TOX_ERR_KEY_DERIVATION_NULL,\n    /**\n     * The crypto lib was unable to derive a key from the given passphrase,\n     * which is usually a lack of memory issue. The functions accepting keys\n     * do not produce this error.\n     */\n    TOX_ERR_KEY_DERIVATION_FAILED\n} TOX_ERR_KEY_DERIVATION;\n\ntypedef enum TOX_ERR_ENCRYPTION {\n    TOX_ERR_ENCRYPTION_OK,\n    /**\n     * Some input data, or maybe the output pointer, was null.\n     */\n    TOX_ERR_ENCRYPTION_NULL,\n    /**\n     * The crypto lib was unable to derive a key from the given passphrase,\n     * which is usually a lack of memory issue. The functions accepting keys\n     * do not produce this error.\n     */\n    TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED,\n    /**\n     * The encryption itself failed.\n     */\n    TOX_ERR_ENCRYPTION_FAILED\n} TOX_ERR_ENCRYPTION;\n\ntypedef enum TOX_ERR_DECRYPTION {\n    TOX_ERR_DECRYPTION_OK,\n    /**\n     * Some input data, or maybe the output pointer, was null.\n     */\n    TOX_ERR_DECRYPTION_NULL,\n    /**\n     * The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes\n     */\n    TOX_ERR_DECRYPTION_INVALID_LENGTH,\n    /**\n     * The input data is missing the magic number (i.e. wasn't created by this\n     * module, or is corrupted)\n     */\n    TOX_ERR_DECRYPTION_BAD_FORMAT,\n    /**\n     * The crypto lib was unable to derive a key from the given passphrase,\n     * which is usually a lack of memory issue. The functions accepting keys\n     * do not produce this error.\n     */\n    TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED,\n    /**\n     * The encrypted byte array could not be decrypted. Either the data was\n     * corrupt or the password/key was incorrect.\n     */\n    TOX_ERR_DECRYPTION_FAILED\n} TOX_ERR_DECRYPTION;\n\n\n/******************************* BEGIN PART 2 *******************************\n * For simplicty, the second part of the module is presented first. The API for\n * the first part is analgous, with some extra functions for key handling. If\n * your code spends too much time using these functions, consider using the part\n * 1 functions instead.\n */\n\n/* Encrypts the given data with the given passphrase. The output array must be\n * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates\n * to tox_derive_key_from_pass and tox_pass_key_encrypt.\n *\n * returns true on success\n */\nbool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passphrase, size_t pplength, uint8_t *out,\n                      TOX_ERR_ENCRYPTION *error);\n\n\n/* Decrypts the given data with the given passphrase. The output array must be\n * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates\n * to tox_pass_key_decrypt.\n *\n * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH\n *\n * returns true on success\n */\nbool tox_pass_decrypt(const uint8_t *data, size_t length, const uint8_t *passphrase, size_t pplength, uint8_t *out,\n                      TOX_ERR_DECRYPTION *error);\n\n\n/******************************* BEGIN PART 1 *******************************\n * And now part \"1\", which does the actual encryption, and is rather less cpu\n * intensive than part one. The first 3 functions are for key handling.\n */\n\n/* This key structure's internals should not be used by any client program, even\n * if they are straightforward here.\n */\ntypedef struct {\n    uint8_t salt[TOX_PASS_SALT_LENGTH];\n    uint8_t key[TOX_PASS_KEY_LENGTH];\n} TOX_PASS_KEY;\n\n/* Generates a secret symmetric key from the given passphrase. out_key must be at least\n * TOX_PASS_KEY_LENGTH bytes long.\n * Be sure to not compromise the key! Only keep it in memory, do not write to disk.\n * The password is zeroed after key derivation.\n * The key should only be used with the other functions in this module, as it\n * includes a salt.\n * Note that this function is not deterministic; to derive the same key from a\n * password, you also must know the random salt that was used. See below.\n *\n * returns true on success\n */\nbool tox_derive_key_from_pass(const uint8_t *passphrase, size_t pplength, TOX_PASS_KEY *out_key,\n                              TOX_ERR_KEY_DERIVATION *error);\n\n/* Same as above, except use the given salt for deterministic key derivation.\n * The salt must be TOX_PASS_SALT_LENGTH bytes in length.\n */\nbool tox_derive_key_with_salt(const uint8_t *passphrase, size_t pplength, const uint8_t *salt, TOX_PASS_KEY *out_key,\n                              TOX_ERR_KEY_DERIVATION *error);\n\n/* This retrieves the salt used to encrypt the given data, which can then be passed to\n * derive_key_with_salt to produce the same key as was previously used. Any encrpyted\n * data with this module can be used as input.\n *\n * returns true if magic number matches\n * success does not say anything about the validity of the data, only that data of\n * the appropriate size was copied\n */\nbool tox_get_salt(const uint8_t *data, uint8_t *salt);\n\n/* Now come the functions that are analogous to the part 2 functions. */\n\n/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output\n * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long.\n * key must be TOX_PASS_KEY_LENGTH bytes.\n * If you already have a symmetric key from somewhere besides this module, simply\n * call encrypt_data_symmetric in toxcore/crypto_core directly.\n *\n * returns true on success\n */\nbool tox_pass_key_encrypt(const uint8_t *data, size_t data_len, const TOX_PASS_KEY *key, uint8_t *out,\n                          TOX_ERR_ENCRYPTION *error);\n\n/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by\n * tox_derive_key_from_pass.\n *\n * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH\n *\n * returns true on success\n */\nbool tox_pass_key_decrypt(const uint8_t *data, size_t length, const TOX_PASS_KEY *key, uint8_t *out,\n                          TOX_ERR_DECRYPTION *error);\n\n/* Determines whether or not the given data is encrypted (by checking the magic number)\n */\nbool tox_is_data_encrypted(const uint8_t *data);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  }
]