diff --git a/.gitignore b/.gitignore index 44b5eb56..62a6c6a1 100755 --- a/.gitignore +++ b/.gitignore @@ -120,3 +120,4 @@ __pycache__ *~ attic/world/*.c25519 attic/world/mkworld +workspace/ diff --git a/AUTHORS.md b/AUTHORS.md index c4c0c730..84bb8631 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,3 +1,5 @@ +# Authors and Third Party Code Licensing Information + ## Primary Authors * ZeroTier Core and ZeroTier One virtual networking service
@@ -26,7 +28,7 @@ ## Third-Party Code -ZeroTier includes the following third party code, either in ext/ or incorporated into the ZeroTier core. +ZeroTier includes the following third party code, either in ext/ or incorporated into the ZeroTier core. This third party code remains licensed under its original license and is not subject to ZeroTier's BSL license. * LZ4 compression algorithm by Yann Collet diff --git a/COPYING b/COPYING index c43e8e7b..d07f3524 100644 --- a/COPYING +++ b/COPYING @@ -1,13 +1,8 @@ ZeroTier One, an endpoint server for the ZeroTier virtual network layer. Copyright © 2011–2019 ZeroTier, Inc. -ZeroTier One is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at -your option) any later version. - -See the file ‘LICENSE.GPL-3’ for the text of the GNU GPL version 3. -If that file is not present, see . +ZeroTier is released under the terms of the BSL version 1.1. See the +file LICENSE.txt for details. .. Local variables: diff --git a/Jenkinsfile b/Jenkinsfile index 88989327..757729e3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,84 +1,365 @@ -#!/usr/bin/env groovy - -node('master') { - checkout scm +pipeline { + options { + disableConcurrentBuilds() + preserveStashes(buildCount: 10) + timestamps() + } + parameters { + booleanParam(name: "BUILD_ALL", defaultValue: false, description: "Build all supported platform/architecture combos. Defaults to x86/x64 only") + } - def changelog = getChangeLog currentBuild - - mattermostSend "Building ${env.JOB_NAME} #${env.BUILD_NUMBER} \n Change Log: \n ${changelog}" -} - -parallel 'centos7': { - node('centos7') { - try { - checkout scm - - stage('Build Centos 7') { - sh 'make -f make-linux.mk' + agent none + + stages { + stage ("Build") { + steps { + script { + def tasks = [:] + tasks << buildStaticBinaries() + tasks << buildDebianNative() + tasks << buildCentosNative() + + parallel tasks + } } } - catch (err) { - currentBuild.result = "FAILURE" - mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Centos 7 (<${env.BUILD_URL}|Open>)" - - throw err + stage ("Package Static") { + steps { + script { + parallel packageStatic() + } + } } } -// }, 'android-ndk': { -// node('android-ndk') { -// try { -// checkout scm - -// stage('Build Android NDK') { -// sh "/android/android-ndk-r15b/ndk-build -C $WORKSPACE/java ZT1=${WORKSPACE}" -// } -// } -// catch (err) { -// currentBuild.result = "FAILURE" -// mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Android NDK (<${env.BUILD_URL}|Open>)" - -// throw err -// } -// } -// }, 'macOS': { -// node('macOS') { -// try { -// checkout scm - -// stage('Build macOS') { -// sh 'make -f make-mac.mk' -// } - -// stage('Build macOS UI') { -// sh 'cd macui && xcodebuild -target "ZeroTier One" -configuration Debug' -// } -// } -// catch (err) { -// currentBuild.result = "FAILURE" -// mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)" - -// throw err -// } -// } -// }, 'windows': { -// node('windows') { -// try { -// checkout scm - -// stage('Build Windows') { -// bat '''CALL "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" amd64 -// git clean -dfx -// msbuild windows\\ZeroTierOne.sln -// ''' -// } -// } -// catch (err) { -// currentBuild.result = "FAILURE" -// mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Windows (<${env.BUILD_URL}|Open>)" - -// throw err -// } -// } } -mattermostSend color: "#00ff00", message: "${env.JOB_NAME} #${env.BUILD_NUMBER} Complete (<${env.BUILD_URL}|Show More...>)" +def buildStaticBinaries() { + def tasks = [:] + def dist = ["alpine"] + def archs = [] + if (params.BUILD_ALL == true) { + archs = ["arm64", "amd64", "i386", "armhf", "armel", "ppc64le", "s390x"] + } else { + archs = ["amd64", "i386"] + } + + tasks << getTasks(dist, archs, { distro, platform -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + sh "echo ${distro}-${platform}" + def runtime = docker.image("ztbuild/${distro}-${platform}:latest") + runtime.inside { + dir("build") { + sh 'make -j8 ZT_STATIC=1 all' + sh "file ./zerotier-one" + sh "mv zerotier-one zerotier-one-static-${platform}" + stash includes: 'zerotier-one-static-*', name: "static-${platform}" + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + } + return myNode + }) + + return tasks +} + +def getTasks(axisDistro, axisPlatform, task) { + def tasks = [:] + for(int i=0; i< axisDistro.size(); i++) { + def axisDistroValue = axisDistro[i] + for(int j=0; j< axisPlatform.size(); j++) { + def axisPlatformValue = axisPlatform[j] + tasks["${axisDistroValue}/${axisPlatformValue}"] = task(axisDistroValue, axisPlatformValue) + } + } + return tasks +} + +def packageStatic() { + def tasks = [:] + + def centos6 = ["centos6"] + def centos6Arch = ["i386", "amd64"] + tasks << getTasks(centos6, centos6Arch, { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + dir("build") { + unstash "static-${arch}" + sh "mv zerotier-one-static-${arch} zerotier-one && chmod +x zerotier-one" + sh "make redhat" + sh "mkdir -p ${distro}" + sh "cp -av `find ~/rpmbuild/ -type f -name \"*.rpm\"` ${distro}/" + archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true + } + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + return myNode + }) + + def centos7 = ["centos7"] + def centos7Arch = ["i386"] + tasks << getTasks(centos7, centos7Arch, { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + dir("build") { + unstash "static-${arch}" + sh "mv zerotier-one-static-${arch} zerotier-one && chmod +x zerotier-one" + sh "make redhat" + sh "mkdir -p ${distro}" + sh "cp -av `find ~/rpmbuild/ -type f -name \"*.rpm\"` ${distro}/" + archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true + } + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + return myNode + }) + + if (params.BUILD_ALL == true) { + def clefos7 = ["clefos"] + def clefos7Arch = ["s390x"] + tasks << getTasks(clefos7, clefos7Arch, { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + dir("build/") { + unstash "static-${arch}" + sh "mv zerotier-one-static-${arch} zerotier-one && chmod +x zerotier-one" + sh "make redhat" + sh "mkdir -p ${distro}" + sh "cp -av `find ~/rpmbuild/ -type f -name \"*.rpm\"` ${distro}/" + archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true + } + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + return myNode + }) + } + + def debianJessie = ["debian-jessie"] + def debianJessieArchs = [] + if (params.BUILD_ALL == true) { + debianJessieArch = ["armhf", "armel", "amd64", "i386"] + } else { + debianJessieArch = ["amd64", "i386"] + } + tasks << getTasks(debianJessie, debianJessieArch, { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + sh "ls -la ." + dir('build/') { + sh "ls -la ." + unstash "static-${arch}" + sh "pwd" + sh "mv zerotier-one-static-${arch} zerotier-one && chmod +x zerotier-one && file ./zerotier-one" + sh "mv -f debian/rules.static debian/rules" + sh "make debian" + } + sh "mkdir -p ${distro}" + sh "mv *.deb ${distro}" + archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + return myNode + }) + + def ubuntuTrusty = ["ubuntu-trusty"] + def ubuntuTrustyArch = [] + if (params.BUILD_ALL == true) { + ubuntuTrustyArch = ["i386", "amd64", "armhf", "arm64", "ppc64le"] + } else { + ubuntuTrustyArch = ["i386", "amd64"] + } + tasks << getTasks(ubuntuTrusty, ubuntuTrustyArch, { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + sh "ls -la ." + dir('build/') { + sh "ls -la ." + unstash "static-${arch}" + sh "pwd" + sh "mv zerotier-one-static-${arch} zerotier-one && chmod +x zerotier-one && file ./zerotier-one" + sh "mv -f debian/rules.static debian/rules" + sh "make debian" + } + sh "mkdir -p ${distro}" + sh "mv *.deb ${distro}" + archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + return myNode + }) + + def debianWheezy = ["debian-wheezy"] + def debianWheezyArchs = [] + if (params.BUILD_ALL == true) { + debianWheezyArchs = ["armhf", "armel", "amd64", "i386"] + } else { + debianWheezyArchs = ["amd64", "i386"] + } + tasks << getTasks(debianJessie, debianJessieArch, { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + dir('build/') { + unstash "static-${arch}" + sh "mv zerotier-one-static-${arch} zerotier-one && chmod +x zerotier-one && file ./zerotier-one" + sh "mv -f debian/rules.wheezy.static debian/rules" + sh "mv -f debian/control.wheezy debian/control" + sh "make debian" + } + sh "mkdir -p ${distro}" + sh "mv *.deb ${distro}" + archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true + } + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + return myNode + }) + + return tasks +} + +def buildDebianNative() { + def tasks = [:] + def buster = ["debian-buster", "debian-stretch", "debian-bullseye", "debian-sid"] + def busterArchs = [] + if (params.BUILD_ALL) { + busterArchs = ["s390x", "ppc64le", "i386", "armhf", "armel", "arm64", "amd64"] + } else { + busterArchs = ["amd64", "i386"] + } + + def build = { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + dir("build") { + sh 'make debian' + } + sh "mkdir -p ${distro}" + sh "mv *.deb ${distro}" + archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + } + return myNode + } + + tasks << getTasks(buster, busterArchs, build) + + // bash is broken when running under QEMU-s390x on Xenial + def xenial = ["ubuntu-xenial"] + def xenialArchs = [] + if (params.BUILD_ALL == true) { + xenialArchs = ["i386", "amd64", "armhf", "arm64", "ppc64le"] + } else { + xenialArchs = ["i386", "amd64"] + } + tasks << getTasks(xenial, xenialArchs, build) + + def ubuntu = ["ubuntu-bionic", "ubuntu-eoan"] + def ubuntuArchs = [] + if (params.BUILD_ALL == true) { + ubuntuArchs = ["i386", "amd64", "armhf", "arm64", "ppc64le", "s390x"] + } else { + ubuntuArchs = ["i386", "amd64"] + } + tasks << getTasks(ubuntu, ubuntuArchs, build) + + def kali = ["kali-rolling"] + def kaliArchs = ["amd64"] + tasks << getTasks(kali, kaliArchs, build) + + return tasks +} + +def buildCentosNative() { + def tasks = [:] + + def build = { distro, arch -> + def myNode = { + node ('linux-build') { + dir ("build") { + checkout scm + } + def runtime = docker.image("ztbuild/${distro}-${arch}:latest") + runtime.inside { + dir("build") { + sh 'make -j4' + sh 'make redhat' + sh "mkdir -p ${distro}" + sh "cp -av `find ~/rpmbuild/ -type f -name \"*.rpm\"` ${distro}/" + archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true + } + + cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true + } + } + } + return myNode + } + + def centos8 = ["centos8"] + def centos8Archs = [] + if (params.BUILD_ALL == true) { + centos8Archs = ["amd64", "arm64", "ppc64le"] + } else { + centos8Archs = ["amd64"] + } + tasks << getTasks(centos8, centos8Archs, build) + + def centos7 = ["centos7"] + def centos7Archs = ["amd64"] + tasks << getTasks(centos7, centos7Archs, build) + + return tasks +} diff --git a/LICENSE.GPL-2 b/LICENSE.GPL-2 deleted file mode 100644 index d159169d..00000000 --- a/LICENSE.GPL-2 +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/LICENSE.GPL-3 b/LICENSE.GPL-3 deleted file mode 100644 index 94a9ed02..00000000 --- a/LICENSE.GPL-3 +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/LICENSE.txt b/LICENSE.txt index 3807fea3..78daf4c2 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,37 +1,149 @@ -ZeroTier One - Network Virtualization Everywhere -Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ +----------------------------------------------------------------------------- -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +Business Source License 1.1 -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. -You should have received a copy of the GNU General Public License -along with this program. If not, see . +----------------------------------------------------------------------------- -See LICENSE.GPL-3 for the full GNU GPL v3 license. +Parameters --- +Licensor: ZeroTier, Inc. +Licensed Work: ZeroTier Network Virtualization Engine 1.4.4 + The Licensed Work is (c)2019 ZeroTier, Inc. +Additional Use Grant: You may make use of the Licensed Work, provided you + do not use it in any of the following ways: -You can be released from the requirements of the license by purchasing -a commercial license. Buying such a license is mandatory as soon as you -develop commercial closed-source software that incorporates or links -directly against ZeroTier software without disclosing the source code -of your own application. + * Sell hosted ZeroTier services as a "SaaS" Product --- + (1) Operate or sell access to ZeroTier root servers, + network controllers, or authorization key or certificate + generation components of the Licensed Work as a + for-profit service, regardless of whether the use of + these components is sold alone or is bundled with other + services. Note that this does not apply to the use of + ZeroTier behind the scenes to operate a service not + related to ZeroTier network administration. -The above license does not apply to third party code included with or -linked against by ZeroTier software. See the third party code section -of the AUTHORS.md for an index of third party software included in -this software repository. + * Create Non-Open-Source Commercial Derviative Works -Licenses for third party code are all relatively permissive: MIT, -BSD, and public domain. The only exception is the tap-windows driver -which is under the GPLv2, but this is only needed to produce the -binary tap device driver used by the ZeroTier service on Windows. + (2) Link or directly include the Licensed Work in a + commercial or for-profit application or other product + not distributed under an Open Source Initiative (OSI) + compliant license. See: https://opensource.org/licenses + + (3) Remove the name, logo, copyright, or other branding + material from the Licensed Work to create a "rebranded" + or "white labeled" version to distribute as part of + any commercial or for-profit product or service. + + * Certain Government Uses + + (4) Use or deploy the Licensed Work in a government + setting in support of any active government function + or operation with the exception of the following: + physical or mental health care, family and social + services, social welfare, senior care, child care, and + the care of persons with disabilities. + +Change Date: 2023-01-01 + +Change License: Apache License version 2.0 as published by the Apache + Software Foundation + https://www.apache.org/licenses/ + +Alternative Licensing + +If you would like to use the Licensed Work in any way that conflicts with +the stipulations of the Additional Use Grant, contact ZeroTier, Inc. to +obtain an alternative commercial license. + +Visit us on the web at: https://www.zerotier.com/ + +Notice + +The Business Source License (this document, or the "License") is not an Open +Source license. However, the Licensed Work will eventually be made available +under an Open Source License, as stated in this License. + +For more information on the use of the Business Source License for ZeroTier +products, please visit our pricing page which contains license details and +and license FAQ: https://zerotier.com/pricing + +For more information on the use of the Business Source License generally, +please visit the Adopting and Developing Business Source License FAQ at +https://mariadb.com/bsl-faq-adopting. + +----------------------------------------------------------------------------- + +Business Source License 1.1 + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative +works, redistribute, and make non-production use of the Licensed Work. The +Licensor may make an Additional Use Grant, above, permitting limited +production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly +available distribution of a specific version of the Licensed Work under this +License, whichever comes first, the Licensor hereby grants you rights under +the terms of the Change License, and the rights granted in the paragraph +above terminate. + +If your use of the Licensed Work does not comply with the requirements +currently in effect as described in this License, you must purchase a +commercial license from the Licensor, its affiliated entities, or authorized +resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works +of the Licensed Work, are subject to this License. This License applies +separately for each version of the Licensed Work and the Change Date may vary +for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy +of the Licensed Work. If you receive the Licensed Work in original or +modified form from a third party, the terms and conditions set forth in this +License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically +terminate your rights under this License for the current and all other +versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of +Licensor or its affiliates (provided that you may use a trademark or logo of +Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +TITLE. + +----------------------------------------------------------------------------- + +MariaDB hereby grants you permission to use this License’s text to license +your works, and to refer to it using the trademark "Business Source License", +as long as you comply with the Covenants of Licensor below. + +Covenants of Licensor + +In consideration of the right to use this License’s text and the "Business +Source License" name and trademark, Licensor covenants to MariaDB, and to all +other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, + or a license that is compatible with GPL Version 2.0 or a later version, + where "compatible" means that software provided under the Change License can + be included in a program with software provided under GPL Version 2.0 or a + later version. Licensor may specify additional Change Licenses without + limitation. + +2. To either: (a) specify an additional grant of rights to use that does not + impose any additional restriction on the right granted in this License, as + the Additional Use Grant; or (b) insert the text "None". + +3. To specify a Change Date. + +4. Not to modify this License in any other way. diff --git a/README.md b/README.md index 6fecf2fd..b571459d 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,27 @@ ZeroTier - Global Area Networking ====== -ZeroTier is a smart programmable Ethernet switch for planet Earth. It allows networked devices and applications to be managed as if the entire world is one data center or cloud region. +ZeroTier is a smart programmable Ethernet switch for planet Earth. It allows all networked devices, VMs, containers, and applications to communicate as if they all reside in the same physical data center or cloud region. -It replaces the physical LAN/WAN boundary with a virtual one, allowing devices of any type at any location to be managed as if they all reside in the same cloud region or data center. All traffic is encrypted end-to-end and takes the most direct path available for minimum latency and maximum performance. The goals and design of ZeroTier are inspired by among other things the original [Google BeyondCorp](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/43231.pdf) paper and the [Jericho Forum](https://en.wikipedia.org/wiki/Jericho_Forum). +This is accomplished by combining a cryptographically addressed and secure peer to peer network (termed VL1) with an Ethernet emulation layer somewhat similar to VXLAN (termed VL2). Our VL2 Ethernet virtualization layer includes advanced enterprise SDN features like fine grained access control rules for network micro-segmentation and security monitoring. + +All ZeroTier traffic is encrypted end-to-end using secret keys that only you control. Most traffic flows peer to peer, though we offer free (but slow) relaying for users who cannot establish peer to peer connetions. + +The goals and design principles of ZeroTier are inspired by among other things the original [Google BeyondCorp](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/43231.pdf) paper and the [Jericho Forum](https://en.wikipedia.org/wiki/Jericho_Forum) with its notion of "deperimeterization." Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre-built binary packages](https://www.zerotier.com/download/). Apps for Android and iOS are available for free in the Google Play and Apple app stores. +ZeroTier is licensed under the [BSL version 1.1](https://mariadb.com/bsl11/). See [LICENSE.txt](LICENSE.txt) and the [ZeroTier pricing page](https://www.zerotier.com/pricing) for details. ZeroTier is free to use internally in businesses and academic institutions and for non-commercial purposes. Certain types of commercial use such as building closed-source apps and devices based on ZeroTier or offering ZeroTier network controllers and network management as a SaaS service require a commercial license. + +A small amount of third party code is also included in ZeroTier and is not subject to our BSL license. See [AUTHORS.md] for a list of third party code, where it is included, and the licenses that apply to it. All of the third party code in ZeroTier is liberally licensed (MIT, BSD, Apache, public domain, etc.). + ### Getting Started -Everything in the ZeroTier world is controlled by two types of identifier: 40-bit/10-digit *ZeroTier addresses* and 64-bit/16-digit *network IDs*. A ZeroTier address identifies a node or "device" (laptop, phone, server, VM, app, etc.) while a network ID identifies a virtual Ethernet network that can be joined by devices. +Everything in the ZeroTier world is controlled by two types of identifier: 40-bit/10-digit *ZeroTier addresses* and 64-bit/16-digit *network IDs*. These identifiers are easily distinguished by their length. A ZeroTier address identifies a node or "device" (laptop, phone, server, VM, app, etc.) while a network ID identifies a virtual Ethernet network that can be joined by devices. -Another way of thinking about it is that ZeroTier addresses are port numbers on a giant planetary-sized smart switch while network IDs are VLANs to which these ports can be assigned. For more details read about VL1 and VL2 in [the ZeroTier manual](https://www.zerotier.com/manual/). +ZeroTier addresses can be thought of as port numbers on an enormous planet-wide enterprise Ethernet smart switch supporting VLANs. Network IDs are VLAN IDs to which these ports may be assigned. A single port can be assigned to more than one VLAN. -*Network controllers* are ZeroTier nodes that act as access control certificate authorities and configuration managers for virtual networks. The first 40 bits (or 10 digits) of a network ID is the ZeroTier address of its controller. You can create networks with our [hosted controllers](https://my.zerotier.com/) and web UI/API or [host your own](controller/) if you don't mind posting some JSON configuration info or writing a script to do so. +A ZeroTier address looks like `8056c2e21c` and a network ID looks like `8056c2e21c000001`. Network IDs are composed of the ZeroTier address of that network's primary controller and an arbitrary 24-bit ID that identifies the network on this controller. Network controllers are roughly analogous to SDN controllers in SDN protocols like [OpenFlow](https://en.wikipedia.org/wiki/OpenFlow), though as with the analogy between VXLAN and VL2 this should not be read to imply that the protocols or design are the same. You can use our convenient and inexpensive SaaS hosted controllers at [my.zerotier.com](https://my.zerotier.com/) or [run your own controller](controller/) if you don't mind messing around with JSON configuration files or writing scripts to do so. ### Project Layout @@ -24,7 +32,6 @@ The base path contains the ZeroTier One service main entry point (`one.cpp`), se - `controller/`: the reference network controller implementation, which is built and included by default on desktop and server build targets. - `debian/`: files for building Debian packages on Linux. - `doc/`: manual pages and other documentation. - - `docker/`: Dockerfile to build as a container for containerized Linux systems and Kubernetes clusters. - `ext/`: third party libraries, binaries that we ship for convenience on some platforms (Mac and Windows), and installation support files. - `include/`: include files for the ZeroTier core. - `java/`: a JNI wrapper used with our Android mobile app. (The whole Android app is not open source but may be made so in the future.) @@ -33,7 +40,7 @@ The base path contains the ZeroTier One service main entry point (`one.cpp`), se - `osdep/`: code to support and integrate with OSes, including platform-specific stuff only built for certain targets. - `rule-compiler/`: JavaScript rules language compiler for defining network-level rules. - `service/`: the ZeroTier One service, which wraps the ZeroTier core and provides VPN-like connectivity to virtual networks for desktops, laptops, servers, VMs, and containers. - - `windows/`: Visual Studio solution files, Windows service code for ZeroTier One, and the Windows task bar app UI. + - `windows/`: Visual Studio solution files, Windows service code, and the Windows task bar app UI. ### Build and Platform Notes @@ -80,7 +87,7 @@ Running ZeroTier One on a Mac is the same, but OSX requires a kernel extension. This will create the home folder for Mac, place *tap.kext* there, and set its modes correctly to enable ZeroTier One to manage it with *kextload* and *kextunload*. -### Troubleshooting +### Basic Troubleshooting For most users, it just works. @@ -96,14 +103,6 @@ ZeroTier One peers will automatically locate each other and communicate directly Users behind certain types of firewalls and "symmetric" NAT devices may not able able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours. -If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226?pk_campaign=github_ZeroTierOne). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport. - If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity. -### Contributing - -Please make pull requests against the `dev` branch. The `master` branch is release, and `edge` is for unstable and work in progress changes and is not likely to work. - -### License - -The ZeroTier source code is open source and is licensed under the GNU GPL v3 (not LGPL). If you'd like to embed it in a closed-source commercial product or appliance, please e-mail [contact@zerotier.com](mailto:contact@zerotier.com) to discuss commercial licensing. Otherwise it can be used for free. +Additional help [can be found in our knowledge base](https://zerotier.atlassian.net/wiki/spaces/SD/overview). diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index a781392d..2f3777b4 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,6 +1,21 @@ ZeroTier Release Notes ====== +# 2019-08-30 -- Version 1.4.6 + + * Update default root list to latest + * ARM32 platform build and flag fixes + * Add a clarification line to LICENSE.txt + * Fix license message in CLI + * Windows service now looks for service command line arguments + * Fixed a bug that could cause excessive queued multicasts + +# 2019-08-23 -- Version 1.4.4 + + * Change license from GPL3 to BSL 1.1, see LICENSE.txt + * Fix an issue with the "ipauth" rule and auto-generated unforgeable IPv6 addresses + * Fix socket/bind errors setting IPs and routes on Linux + # 2019-08-12 -- Version 1.4.2 * Fix high CPU use bug on some platforms diff --git a/attic/world/build.sh b/attic/world/build.sh index aeb3b87f..d8800cd4 100755 --- a/attic/world/build.sh +++ b/attic/world/build.sh @@ -1,3 +1,3 @@ #!/bin/bash -c++ -std=c++11 -I../.. -I.. -O -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm +c++ -std=c++11 -I../.. -I.. -g -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm diff --git a/attic/world/mkworld.cpp b/attic/world/mkworld.cpp index b8cb027b..6b9bbe8d 100644 --- a/attic/world/mkworld.cpp +++ b/attic/world/mkworld.cpp @@ -81,44 +81,63 @@ int main(int argc,char **argv) std::vector roots; const uint64_t id = ZT_WORLD_ID_EARTH; - const uint64_t ts = 1562631342273ULL; // July 8th, 2019 + const uint64_t ts = 1567191349589ULL; // August 30th, 2019 + // Los Angeles roots.push_back(World::Root()); roots.back().identity = Identity("3a46f1bf30:0:76e66fab33e28549a62ee2064d1843273c2c300ba45c3f20bef02dbad225723bb59a9bb4b13535730961aeecf5a163ace477cceb0727025b99ac14a5166a09a3"); roots.back().stableEndpoints.push_back(InetAddress("185.180.13.82/9993")); roots.back().stableEndpoints.push_back(InetAddress("2a02:6ea0:c815::/9993")); - // Alice + // Miami roots.push_back(World::Root()); - roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); - roots.back().stableEndpoints.push_back(InetAddress("188.166.94.177/9993")); // Amsterdam - roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:2:d0::7d:1/9993")); // Amsterdam - roots.back().stableEndpoints.push_back(InetAddress("154.66.197.33/9993")); // Johannesburg - roots.back().stableEndpoints.push_back(InetAddress("2c0f:f850:154:197::33/9993")); // Johannesburg - roots.back().stableEndpoints.push_back(InetAddress("159.203.97.171/9993")); // New York - roots.back().stableEndpoints.push_back(InetAddress("2604:a880:800:a1::54:6001/9993")); // New York - roots.back().stableEndpoints.push_back(InetAddress("131.255.6.16/9993")); // Buenos Aires - roots.back().stableEndpoints.push_back(InetAddress("2803:eb80:0:e::2/9993")); // Buenos Aires - roots.back().stableEndpoints.push_back(InetAddress("107.170.197.14/9993")); // San Francisco - roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::200:e001/9993")); // San Francisco - roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); // Singapore - roots.back().stableEndpoints.push_back(InetAddress("2400:6180:0:d0::b7:4001/9993")); // Singapore + roots.back().identity = Identity("de8950a8b2:0:1b3ada8251b91b6b6fa6535b8c7e2460918f4f729abdec97d3c7f3796868fb02f0de0b0ee554b2d59fc3524743eebfcf5315e790ed6d92db5bd10c28c09b40ef"); + roots.back().stableEndpoints.push_back(InetAddress("207.246.73.245/443")); + roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:9002:5cb:ec4:7aff:fe8f:69d9/443")); + + // Tokyo + roots.push_back(World::Root()); + roots.back().identity = Identity("34e0a5e174:0:93efb50934788f856d5cfb9ca5be88e85b40965586b75befac900df77352c145a1ba7007569d37c77bfe52c0999f3bdc67a47a4a6000b720a883ce47aa2fb7f8"); + roots.back().stableEndpoints.push_back(InetAddress("147.75.92.2/443")); + roots.back().stableEndpoints.push_back(InetAddress("2604:1380:3000:7100::1/443")); + + // Amsterdam + roots.push_back(World::Root()); + roots.back().identity = Identity("992fcf1db7:0:206ed59350b31916f749a1f85dffb3a8787dcbf83b8c6e9448d4e3ea0e3369301be716c3609344a9d1533850fb4460c50af43322bcfc8e13d3301a1f1003ceb6"); + roots.back().stableEndpoints.push_back(InetAddress("195.181.173.159/443")); + roots.back().stableEndpoints.push_back(InetAddress("2a02:6ea0:c024::/443")); + + // Alice + //roots.push_back(World::Root()); + //roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e"); + //roots.back().stableEndpoints.push_back(InetAddress("188.166.94.177/9993")); // Amsterdam + //roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:2:d0::7d:1/9993")); // Amsterdam + //roots.back().stableEndpoints.push_back(InetAddress("154.66.197.33/9993")); // Johannesburg + //roots.back().stableEndpoints.push_back(InetAddress("2c0f:f850:154:197::33/9993")); // Johannesburg + //roots.back().stableEndpoints.push_back(InetAddress("159.203.97.171/9993")); // New York + //roots.back().stableEndpoints.push_back(InetAddress("2604:a880:800:a1::54:6001/9993")); // New York + //roots.back().stableEndpoints.push_back(InetAddress("131.255.6.16/9993")); // Buenos Aires + //roots.back().stableEndpoints.push_back(InetAddress("2803:eb80:0:e::2/9993")); // Buenos Aires + //roots.back().stableEndpoints.push_back(InetAddress("107.170.197.14/9993")); // San Francisco + //roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::200:e001/9993")); // San Francisco + //roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); // Singapore + //roots.back().stableEndpoints.push_back(InetAddress("2400:6180:0:d0::b7:4001/9993")); // Singapore // Bob - roots.push_back(World::Root()); - roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); - roots.back().stableEndpoints.push_back(InetAddress("45.32.198.130/9993")); // Dallas - roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6400:81c3:5400:00ff:fe18:1d61/9993")); // Dallas - roots.back().stableEndpoints.push_back(InetAddress("46.101.160.249/9993")); // Frankfurt - roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:3:d0::6a:3001/9993")); // Frankfurt - roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); // Paris - roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6800:83a4::64/9993")); // Paris - roots.back().stableEndpoints.push_back(InetAddress("45.32.246.179/9993")); // Sydney - roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:5800:8bf8:5400:ff:fe15:b39a/9993")); // Sydney - roots.back().stableEndpoints.push_back(InetAddress("45.32.248.87/9993")); // Tokyo - roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:7000:9bc9:5400:00ff:fe15:c4f5/9993")); // Tokyo - roots.back().stableEndpoints.push_back(InetAddress("159.203.2.154/9993")); // Toronto - roots.back().stableEndpoints.push_back(InetAddress("2604:a880:cad:d0::26:7001/9993")); // Toronto + //roots.push_back(World::Root()); + //roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c"); + //roots.back().stableEndpoints.push_back(InetAddress("45.32.198.130/9993")); // Dallas + //roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6400:81c3:5400:00ff:fe18:1d61/9993")); // Dallas + //roots.back().stableEndpoints.push_back(InetAddress("46.101.160.249/9993")); // Frankfurt + //roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:3:d0::6a:3001/9993")); // Frankfurt + //roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); // Paris + //roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6800:83a4::64/9993")); // Paris + //roots.back().stableEndpoints.push_back(InetAddress("45.32.246.179/9993")); // Sydney + //roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:5800:8bf8:5400:ff:fe15:b39a/9993")); // Sydney + //roots.back().stableEndpoints.push_back(InetAddress("45.32.248.87/9993")); // Tokyo + //roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:7000:9bc9:5400:00ff:fe15:c4f5/9993")); // Tokyo + //roots.back().stableEndpoints.push_back(InetAddress("159.203.2.154/9993")); // Toronto + //roots.back().stableEndpoints.push_back(InetAddress("2604:a880:cad:d0::26:7001/9993")); // Toronto // END WORLD DEFINITION // ========================================================================= diff --git a/attic/world/world.bin b/attic/world/world.bin index fff7e2a9..88049ccd 100644 Binary files a/attic/world/world.bin and b/attic/world/world.bin differ diff --git a/controller/DB.cpp b/controller/DB.cpp index 0c6274b9..dfa4fa09 100644 --- a/controller/DB.cpp +++ b/controller/DB.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "DB.hpp" #include "EmbeddedNetworkController.hpp" diff --git a/controller/DB.hpp b/controller/DB.hpp index 6c518426..8a3c05e0 100644 --- a/controller/DB.hpp +++ b/controller/DB.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CONTROLLER_DB_HPP #define ZT_CONTROLLER_DB_HPP diff --git a/controller/DBMirrorSet.cpp b/controller/DBMirrorSet.cpp index c3cd7841..b2c7c71b 100644 --- a/controller/DBMirrorSet.cpp +++ b/controller/DBMirrorSet.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "DBMirrorSet.hpp" diff --git a/controller/DBMirrorSet.hpp b/controller/DBMirrorSet.hpp index 23cb25e7..6ca6c452 100644 --- a/controller/DBMirrorSet.hpp +++ b/controller/DBMirrorSet.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_DBMIRRORSET_HPP #define ZT_DBMIRRORSET_HPP diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 08d31bee..ef2ce2cf 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -469,15 +456,14 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) } // anonymous namespace -EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc) : +EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort) : _startTime(OSUtils::now()), _listenPort(listenPort), _node(node), _ztPath(ztPath), _path(dbPath), _sender((NetworkController::Sender *)0), - _db(this), - _mqc(mqc) + _db(this) { } @@ -498,7 +484,7 @@ void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender) #ifdef ZT_CONTROLLER_USE_LIBPQ if ((_path.length() > 9)&&(_path.substr(0,9) == "postgres:")) { - _db.addDB(std::shared_ptr(new PostgreSQL(_signingId,_path.substr(9).c_str(), _listenPort, _mqc))); + _db.addDB(std::shared_ptr(new PostgreSQL(_signingId,_path.substr(9).c_str(), _listenPort))); } else { #endif _db.addDB(std::shared_ptr(new FileDB(_path.c_str()))); @@ -1650,7 +1636,7 @@ void EmbeddedNetworkController::_request( if ((ipRangeEnd < ipRangeStart)||(ipRangeStart == 0)) continue; uint32_t ipRangeLen = ipRangeEnd - ipRangeStart; - + // Start with the LSB of the member's address uint32_t ipTrialCounter = (uint32_t)(identity.address().toInt() & 0xffffffff); diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index adc2a2ec..d09e08ac 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_SQLITENETWORKCONTROLLER_HPP #define ZT_SQLITENETWORKCONTROLLER_HPP @@ -57,8 +44,6 @@ namespace ZeroTier { class Node; -struct MQConfig; - class EmbeddedNetworkController : public NetworkController,public DB::ChangeListener { public: @@ -66,7 +51,7 @@ public: * @param node Parent node * @param dbPath Database path (file path or database credentials) */ - EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc = NULL); + EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort); virtual ~EmbeddedNetworkController(); virtual void init(const Identity &signingId,Sender *sender); @@ -163,8 +148,6 @@ private: std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus; std::mutex _memberStatus_l; - - MQConfig *_mqc; }; } // namespace ZeroTier diff --git a/controller/FileDB.cpp b/controller/FileDB.cpp index cf5847d6..b4eaf58c 100644 --- a/controller/FileDB.cpp +++ b/controller/FileDB.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "FileDB.hpp" diff --git a/controller/FileDB.hpp b/controller/FileDB.hpp index 8aa2c18e..fcd7af0f 100644 --- a/controller/FileDB.hpp +++ b/controller/FileDB.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CONTROLLER_FILEDB_HPP #define ZT_CONTROLLER_FILEDB_HPP diff --git a/controller/LFDB.cpp b/controller/LFDB.cpp index b6dc6657..d11b77a0 100644 --- a/controller/LFDB.cpp +++ b/controller/LFDB.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "LFDB.hpp" diff --git a/controller/LFDB.hpp b/controller/LFDB.hpp index bcd6cdd0..0849ae57 100644 --- a/controller/LFDB.hpp +++ b/controller/LFDB.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CONTROLLER_LFDB_HPP #define ZT_CONTROLLER_LFDB_HPP @@ -96,7 +83,7 @@ protected: std::thread _syncThread; bool _storeOnlineState; }; - + } // namespace ZeroTier #endif diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index 0c345c90..72acdca9 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "PostgreSQL.hpp" @@ -30,13 +17,12 @@ #include "../node/Constants.hpp" #include "EmbeddedNetworkController.hpp" -#include "RabbitMQ.hpp" #include "../version.h" +#include "hiredis.h" #include #include -#include -#include + using json = nlohmann::json; @@ -82,7 +68,7 @@ std::string join(const std::vector &elements, const char * const se using namespace ZeroTier; -PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, MQConfig *mqc) +PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort) : DB() , _myId(myId) , _myAddress(myId.address()) @@ -91,7 +77,6 @@ PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, M , _run(1) , _waitNoticePrinted(false) , _listenPort(listenPort) - , _mqc(mqc) { char myAddress[64]; _myAddressStr = myId.address().toString(myAddress); @@ -141,7 +126,7 @@ PostgreSQL::~PostgreSQL() { _run = 0; std::this_thread::sleep_for(std::chrono::milliseconds(100)); - + _heartbeatThread.join(); _membersDbWatcher.join(); _networksDbWatcher.join(); @@ -222,7 +207,7 @@ void PostgreSQL::eraseNetwork(const uint64_t networkId) _commitQueue.post(tmp); } -void PostgreSQL::eraseMember(const uint64_t networkId, const uint64_t memberId) +void PostgreSQL::eraseMember(const uint64_t networkId, const uint64_t memberId) { char tmp2[24]; std::pair tmp; @@ -267,7 +252,7 @@ void PostgreSQL::initializeNetworks(PGconn *conn) NULL, NULL, 0); - + if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Networks Initialization Failed: %s", PQerrorMessage(conn)); PQclear(res); @@ -339,7 +324,7 @@ void PostgreSQL::initializeNetworks(PGconn *conn) NULL, NULL, 0); - + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { fprintf(stderr, "ERROR: Error retreiving IP pools for network: %s\n", PQresultErrorMessage(r2)); PQclear(r2); @@ -391,7 +376,7 @@ void PostgreSQL::initializeNetworks(PGconn *conn) } PQclear(r2); - + _networkChanged(empty, config, false); } @@ -543,7 +528,12 @@ void PostgreSQL::initializeMembers(PGconn *conn) int n = PQntuples(r2); for (int j = 0; j < n; ++j) { - config["ipAssignments"].push_back(PQgetvalue(r2, j, 0)); + std::string ipaddr = PQgetvalue(r2, j, 0); + std::size_t pos = ipaddr.find('/'); + if (pos != std::string::npos) { + ipaddr = ipaddr.substr(0, pos); + } + config["ipAssignments"].push_back(ipaddr); } _memberChanged(empty, config, false); @@ -601,7 +591,7 @@ void PostgreSQL::heartbeat() std::string build = std::to_string(ZEROTIER_ONE_VERSION_BUILD); std::string now = std::to_string(OSUtils::now()); std::string host_port = std::to_string(_listenPort); - std::string use_rabbitmq = (_mqc != NULL) ? "true" : "false"; + std::string use_rabbitmq = (false) ? "true" : "false"; const char *values[10] = { controllerId, hostname, @@ -616,7 +606,7 @@ void PostgreSQL::heartbeat() }; PGresult *res = PQexecParams(conn, - "INSERT INTO ztc_controller (id, cluster_host, last_alive, public_identity, v_major, v_minor, v_rev, v_build, host_port, use_rabbitmq) " + "INSERT INTO ztc_controller (id, cluster_host, last_alive, public_identity, v_major, v_minor, v_rev, v_build, host_port, use_rabbitmq) " "VALUES ($1, $2, TO_TIMESTAMP($3::double precision/1000), $4, $5, $6, $7, $8, $9, $10) " "ON CONFLICT (id) DO UPDATE SET cluster_host = EXCLUDED.cluster_host, last_alive = EXCLUDED.last_alive, " "public_identity = EXCLUDED.public_identity, v_major = EXCLUDED.v_major, v_minor = EXCLUDED.v_minor, " @@ -653,10 +643,10 @@ void PostgreSQL::membersDbWatcher() initializeMembers(conn); - if (this->_mqc != NULL) { - PQfinish(conn); - conn = NULL; - _membersWatcher_RabbitMQ(); + if (false) { + // PQfinish(conn); + // conn = NULL; + // _membersWatcher_RabbitMQ(); } else { _membersWatcher_Postgres(conn); PQfinish(conn); @@ -711,41 +701,9 @@ void PostgreSQL::_membersWatcher_Postgres(PGconn *conn) { } } -void PostgreSQL::_membersWatcher_RabbitMQ() { - char buf[11] = {0}; - std::string qname = "member_"+ std::string(_myAddress.toString(buf)); - RabbitMQ rmq(_mqc, qname.c_str()); - try { - rmq.init(); - } catch (std::runtime_error &e) { - fprintf(stderr, "RABBITMQ ERROR: %s\n", e.what()); - exit(11); - } - while (_run == 1) { - try { - std::string msg = rmq.consume(); - // fprintf(stderr, "Got Member Update: %s\n", msg.c_str()); - if (msg.empty()) { - continue; - } - json tmp(json::parse(msg)); - json &ov = tmp["old_val"]; - json &nv = tmp["new_val"]; - json oldConfig, newConfig; - if (ov.is_object()) oldConfig = ov; - if (nv.is_object()) newConfig = nv; - if (oldConfig.is_object() || newConfig.is_object()) { - _memberChanged(oldConfig,newConfig,(this->_ready>=2)); - } - } catch (std::runtime_error &e) { - fprintf(stderr, "RABBITMQ ERROR member change: %s\n", e.what()); - break; - } catch(std::exception &e ) { - fprintf(stderr, "RABBITMQ ERROR member change: %s\n", e.what()); - } catch(...) { - fprintf(stderr, "RABBITMQ ERROR member change: unknown error\n"); - } - } +void PostgreSQL::_membersWatcher_Reids() { + char buff[11] = {0}; + } void PostgreSQL::networksDbWatcher() @@ -759,21 +717,21 @@ void PostgreSQL::networksDbWatcher() initializeNetworks(conn); - if (this->_mqc != NULL) { - PQfinish(conn); - conn = NULL; - _networksWatcher_RabbitMQ(); + if (false) { + // PQfinish(conn); + // conn = NULL; + // _networksWatcher_RabbitMQ(); } else { _networksWatcher_Postgres(conn); PQfinish(conn); conn = NULL; } - + if (_run == 1) { fprintf(stderr, "ERROR: %s networksDbWatcher should still be running! Exiting Controller.\n", _myAddressStr.c_str()); exit(8); } - fprintf(stderr, "Exited membersDbWatcher\n"); + fprintf(stderr, "Exited networksDbWatcher\n"); } void PostgreSQL::_networksWatcher_Postgres(PGconn *conn) { @@ -815,41 +773,8 @@ void PostgreSQL::_networksWatcher_Postgres(PGconn *conn) { } } -void PostgreSQL::_networksWatcher_RabbitMQ() { - char buf[11] = {0}; - std::string qname = "network_"+ std::string(_myAddress.toString(buf)); - RabbitMQ rmq(_mqc, qname.c_str()); - try { - rmq.init(); - } catch (std::runtime_error &e) { - fprintf(stderr, "RABBITMQ ERROR: %s\n", e.what()); - exit(11); - } - while (_run == 1) { - try { - std::string msg = rmq.consume(); - if (msg.empty()) { - continue; - } - // fprintf(stderr, "Got network update: %s\n", msg.c_str()); - json tmp(json::parse(msg)); - json &ov = tmp["old_val"]; - json &nv = tmp["new_val"]; - json oldConfig, newConfig; - if (ov.is_object()) oldConfig = ov; - if (nv.is_object()) newConfig = nv; - if (oldConfig.is_object()||newConfig.is_object()) { - _networkChanged(oldConfig,newConfig,(this->_ready >= 2)); - } - } catch (std::runtime_error &e) { - fprintf(stderr, "RABBITMQ ERROR: %s\n", e.what()); - break; - } catch (std::exception &e) { - fprintf(stderr, "RABBITMQ ERROR network watcher: %s\n", e.what()); - } catch(...) { - fprintf(stderr, "RABBITMQ ERROR network watcher: unknown error\n"); - } - } +void PostgreSQL::_networksWatcher_Redis() { + } void PostgreSQL::commitThread() @@ -934,7 +859,7 @@ void PostgreSQL::commitThread() NULL, NULL, 0); - + if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "ERROR: Error updating member: %s\n", PQresultErrorMessage(res)); fprintf(stderr, "%s", OSUtils::jsonDump(*config, 2).c_str()); @@ -997,20 +922,21 @@ void PostgreSQL::commitThread() }; res = PQexecParams(conn, - "INSERT INTO ztc_member_ip_assignment (member_id, network_id, address) VALUES ($1, $2, $3)", + "INSERT INTO ztc_member_ip_assignment (member_id, network_id, address) VALUES ($1, $2, $3) ON CONFLICT (network_id, member_id, address) DO NOTHING", 3, NULL, v3, NULL, NULL, 0); - + if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "ERROR: Error setting IP addresses for member: %s\n", PQresultErrorMessage(res)); PQclear(res); PQclear(PQexec(conn, "ROLLBACK")); break;; } + assignments.push_back(addr); } res = PQexec(conn, "COMMIT"); @@ -1029,7 +955,7 @@ void PostgreSQL::commitThread() nlohmann::json memNew(*config); get(nwidInt, nwOrig, memberidInt, memOrig); - + _memberChanged(memOrig, memNew, qitem.second); } else { fprintf(stderr, "Can't notify of change. Error parsing nwid or memberid: %llu-%llu\n", (unsigned long long)nwidInt, (unsigned long long)memberidInt); @@ -1111,7 +1037,7 @@ void PostgreSQL::commitThread() NULL, NULL, 0); - + if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "ERROR: Error updating network record: %s\n", PQresultErrorMessage(res)); PQclear(res); @@ -1136,7 +1062,7 @@ void PostgreSQL::commitThread() const char *params[1] = { id.c_str() }; - res = PQexecParams(conn, + res = PQexecParams(conn, "DELETE FROM ztc_network_assignment_pool WHERE network_id = $1", 1, NULL, @@ -1190,7 +1116,7 @@ void PostgreSQL::commitThread() continue; } - res = PQexecParams(conn, + res = PQexecParams(conn, "DELETE FROM ztc_network_route WHERE network_id = $1", 1, NULL, @@ -1295,7 +1221,7 @@ void PostgreSQL::commitThread() NULL, NULL, 0); - + if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "ERROR: Error deleting network: %s\n", PQresultErrorMessage(res)); } @@ -1395,16 +1321,16 @@ void PostgreSQL::onlineNotificationThread() if (found == _networks.end()) { continue; // skip members trying to join non-existant networks } - + std::string networkId(nwidTmp); std::string memberId(memTmp); - + std::vector &members = updateMap[networkId]; members.push_back(memberId); lastOnlineCumulative[i->first] = i->second.first; - - + + const char *qvals[2] = { networkId.c_str(), memberId.c_str() @@ -1432,7 +1358,7 @@ void PostgreSQL::onlineNotificationThread() int64_t ts = i->second.first; std::string ipAddr = i->second.second.toIpString(ipTmp); std::string timestamp = std::to_string(ts); - + if (firstRun) { firstRun = false; } else { @@ -1481,7 +1407,7 @@ PGconn *PostgreSQL::getPgConn(OverrideMode m) if (connStr != NULL) { fprintf(stderr, "PGBouncer Override\n"); std::string conn(connStr); - conn += " application_name=controller-"; + conn += " application_name=controller-"; conn += _myAddressStr.c_str(); return PQconnectdb(conn.c_str()); } diff --git a/controller/PostgreSQL.hpp b/controller/PostgreSQL.hpp index 6b0ea996..dcad35e7 100644 --- a/controller/PostgreSQL.hpp +++ b/controller/PostgreSQL.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "DB.hpp" @@ -39,8 +26,6 @@ typedef struct pg_conn PGconn; namespace ZeroTier { -struct MQConfig; - /** * A controller database driver that talks to PostgreSQL * @@ -50,7 +35,7 @@ struct MQConfig; class PostgreSQL : public DB { public: - PostgreSQL(const Identity &myId, const char *path, int listenPort, MQConfig *mqc = NULL); + PostgreSQL(const Identity &myId, const char *path, int listenPort); virtual ~PostgreSQL(); virtual bool waitForReady(); @@ -72,10 +57,11 @@ private: void heartbeat(); void membersDbWatcher(); void _membersWatcher_Postgres(PGconn *conn); - void _membersWatcher_RabbitMQ(); void networksDbWatcher(); void _networksWatcher_Postgres(PGconn *conn); - void _networksWatcher_RabbitMQ(); + + void _membersWatcher_Reids(); + void _networksWatcher_Redis(); void commitThread(); void onlineNotificationThread(); @@ -108,8 +94,6 @@ private: mutable volatile bool _waitNoticePrinted; int _listenPort; - - MQConfig *_mqc; }; } // namespace ZeroTier diff --git a/controller/README.md b/controller/README.md index c93c08f5..368613a6 100644 --- a/controller/README.md +++ b/controller/README.md @@ -92,7 +92,6 @@ Example: | v6AssignMode | object | IPv6 management and assign options (see below) | YES | | mtu | integer | Network MTU (default: 2800) | YES | | multicastLimit | integer | Maximum recipients for a multicast packet | YES | -| creationTime | integer | Time network was first created | no | | revision | integer | Network config revision counter | no | | routes | array[object] | Managed IPv4 and IPv6 routes; see below | YES | | ipAssignmentPools | array[object] | IP auto-assign ranges; see below | YES | diff --git a/controller/RabbitMQ.cpp b/controller/RabbitMQ.cpp deleted file mode 100644 index e14fbf3f..00000000 --- a/controller/RabbitMQ.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. - */ - - -#include "RabbitMQ.hpp" - -#ifdef ZT_CONTROLLER_USE_LIBPQ - -#include -#include -#include -#include - -namespace ZeroTier -{ - -RabbitMQ::RabbitMQ(MQConfig *cfg, const char *queueName) - : _mqc(cfg) - , _qName(queueName) - , _socket(NULL) - , _status(0) -{ -} - -RabbitMQ::~RabbitMQ() -{ - amqp_channel_close(_conn, _channel, AMQP_REPLY_SUCCESS); - amqp_connection_close(_conn, AMQP_REPLY_SUCCESS); - amqp_destroy_connection(_conn); -} - -void RabbitMQ::init() -{ - struct timeval tval; - memset(&tval, 0, sizeof(struct timeval)); - tval.tv_sec = 5; - - fprintf(stderr, "Initializing RabbitMQ %s\n", _qName); - _conn = amqp_new_connection(); - _socket = amqp_tcp_socket_new(_conn); - if (!_socket) { - throw std::runtime_error("Can't create socket for RabbitMQ"); - } - - _status = amqp_socket_open_noblock(_socket, _mqc->host, _mqc->port, &tval); - if (_status) { - throw std::runtime_error("Can't connect to RabbitMQ"); - } - - amqp_rpc_reply_t r = amqp_login(_conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, - _mqc->username, _mqc->password); - if (r.reply_type != AMQP_RESPONSE_NORMAL) { - throw std::runtime_error("RabbitMQ Login Error"); - } - - static int chan = 0; - { - Mutex::Lock l(_chan_m); - _channel = ++chan; - } - amqp_channel_open(_conn, _channel); - r = amqp_get_rpc_reply(_conn); - if(r.reply_type != AMQP_RESPONSE_NORMAL) { - throw std::runtime_error("Error opening communication channel"); - } - - _q = amqp_queue_declare(_conn, _channel, amqp_cstring_bytes(_qName), 0, 0, 0, 0, amqp_empty_table); - r = amqp_get_rpc_reply(_conn); - if (r.reply_type != AMQP_RESPONSE_NORMAL) { - throw std::runtime_error("Error declaring queue " + std::string(_qName)); - } - - amqp_basic_consume(_conn, _channel, amqp_cstring_bytes(_qName), amqp_empty_bytes, 0, 1, 0, amqp_empty_table); - r = amqp_get_rpc_reply(_conn); - if (r.reply_type != AMQP_RESPONSE_NORMAL) { - throw std::runtime_error("Error consuming queue " + std::string(_qName)); - } - fprintf(stderr, "RabbitMQ Init OK %s\n", _qName); -} - -std::string RabbitMQ::consume() -{ - amqp_rpc_reply_t res; - amqp_envelope_t envelope; - amqp_maybe_release_buffers(_conn); - - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - res = amqp_consume_message(_conn, &envelope, &timeout, 0); - if (res.reply_type != AMQP_RESPONSE_NORMAL) { - if (res.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION && res.library_error == AMQP_STATUS_TIMEOUT) { - // timeout waiting for message. Return empty string - return ""; - } else { - throw std::runtime_error("Error getting message"); - } - } - - std::string msg( - (const char*)envelope.message.body.bytes, - envelope.message.body.len - ); - amqp_destroy_envelope(&envelope); - return msg; -} - -} - -#endif // ZT_CONTROLLER_USE_LIBPQ diff --git a/controller/RabbitMQ.hpp b/controller/RabbitMQ.hpp deleted file mode 100644 index c8ef31ca..00000000 --- a/controller/RabbitMQ.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. - */ - -#ifndef ZT_CONTROLLER_RABBITMQ_HPP -#define ZT_CONTROLLER_RABBITMQ_HPP - -#include "DB.hpp" - -namespace ZeroTier -{ -struct MQConfig { - const char *host; - int port; - const char *username; - const char *password; -}; -} - -#ifdef ZT_CONTROLLER_USE_LIBPQ - -#include "../node/Mutex.hpp" - -#include -#include -#include - -namespace ZeroTier -{ - -class RabbitMQ { -public: - RabbitMQ(MQConfig *cfg, const char *queueName); - ~RabbitMQ(); - - void init(); - - std::string consume(); - -private: - MQConfig *_mqc; - const char *_qName; - - amqp_socket_t *_socket; - amqp_connection_state_t _conn; - amqp_queue_declare_ok_t *_q; - int _status; - - int _channel; - - Mutex _chan_m; -}; - -} - -#endif // ZT_CONTROLLER_USE_LIBPQ - -#endif // ZT_CONTROLLER_RABBITMQ_HPP - diff --git a/debian/changelog b/debian/changelog index 0bf2307a..dc836339 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +zerotier-one (1.4.6) unstable; urgency=medium + + * Update default root server list + * Fix build flags on "armhf" (32-bit ARM) platforms for better + compatibility with Pi Zero and other devices. + * Fix license text in one.cpp. + * Add a clarification to LICENSE.txt. + + -- Adam Ierymenko Fri, 30 Aug 2019 01:00:00 -0700 + +zerotier-one (1.4.4) unstable; urgency=medium + + * See https://github.com/zerotier/ZeroTierOne for release notes. + * License changed to BSL 1.1 + + -- Adam Ierymenko Fri, 23 Aug 2019 01:00:00 -0700 + zerotier-one (1.4.2-2) unstable; urgency=medium * See https://github.com/zerotier/ZeroTierOne for release notes. diff --git a/debian/copyright b/debian/copyright index cd728a0d..493e6a27 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,21 +4,15 @@ Source: https://github.com/zerotier/ZeroTierOne Files: * Copyright: 2011-2016 ZeroTier, Inc. -License: GPL-3.0+ +License: ZeroTier BSL 1.1 -License: GPL-3.0+ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . - . - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". +License: ZeroTier BSL 1.1 + Copyright (c)2019 ZeroTier, Inc. + + Use of this software is governed by the Business Source License included + in the LICENSE.TXT file in the project's root directory. + + Change Date: 2023-01-01 + + On the date above, in accordance with the Business Source License, use + of this software will be governed by version 2.0 of the Apache License. diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 0f0750c6..00000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -# Dockerfile for ZeroTier Central Controllers -FROM centos:7 -MAINTAINER Adam Ierymekno , Grant Limberg - -RUN yum update -y -RUN yum install -y https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm -RUN yum install -y bash postgresql10 libpqxx-devel - -RUN yum -y install epel-release && yum -y update && yum clean all -RUN yum -y install clang jemalloc jemalloc-devel - - -ADD zerotier-one /usr/local/bin/zerotier-one -RUN chmod a+x /usr/local/bin/zerotier-one - -ADD docker/main.sh / -RUN chmod a+x /main.sh - -ENTRYPOINT /main.sh diff --git a/dockerbuild/Dockerfile.alpine b/dockerbuild/Dockerfile.alpine new file mode 100644 index 00000000..1610ce52 --- /dev/null +++ b/dockerbuild/Dockerfile.alpine @@ -0,0 +1,23 @@ +FROM alpine:3.11.3 + +ARG go_pkg_url + +RUN apk add --update alpine-sdk linux-headers cmake openssh curl + + +RUN adduser -D -s /bin/ash jenkins && \ + passwd -u jenkins && \ + ssh-keygen -A && \ + mkdir /home/jenkins/.ssh && \ + chown -R jenkins:jenkins /home/jenkins + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz + +COPY authorized_keys /home/jenkins/.ssh/authorized_keys +RUN chown -R jenkins:jenkins /home/jenkins/.ssh && \ + chmod 600 /home/jenkins/.ssh/authorized_keys + +EXPOSE 22 +CMD ["/usr/sbin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.centos6 b/dockerbuild/Dockerfile.centos6 new file mode 100644 index 00000000..6b8f023e --- /dev/null +++ b/dockerbuild/Dockerfile.centos6 @@ -0,0 +1,20 @@ +FROM centos:6 + +ARG go_pkg_url + +RUN yum update -y +RUN yum install -y curl git wget openssh-server sudo make rpmdevtools && yum clean all + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build + +RUN echo $'\n\ + export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ + >> ~/.bash_profile + +RUN mkdir /rpmbuild && chmod 777 /rpmbuild + +CMD ["/usr/sbin/sshd", "-D"] diff --git a/dockerbuild/Dockerfile.centos6-i386 b/dockerbuild/Dockerfile.centos6-i386 new file mode 100644 index 00000000..c6a47072 --- /dev/null +++ b/dockerbuild/Dockerfile.centos6-i386 @@ -0,0 +1,21 @@ +FROM i386/centos:6 + +ARG go_pkg_url + +RUN echo i386 > /etc/yum/vars/basearch && echo i686 > /etc/yum/vars/arch + +RUN yum install -y curl git wget openssh-server sudo make rpmdevtools && yum clean all + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build + +RUN echo $'\n\ + export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ + >> ~/.bash_profile + +RUN mkdir /rpmbuild && chmod 777 /rpmbuild + +CMD ["/usr/sbin/sshd", "-D"] diff --git a/dockerbuild/Dockerfile.centos7 b/dockerbuild/Dockerfile.centos7 new file mode 100644 index 00000000..751d02c0 --- /dev/null +++ b/dockerbuild/Dockerfile.centos7 @@ -0,0 +1,25 @@ +FROM centos:7 + +ARG go_pkg_url + +RUN yum install -y epel-release +RUN yum install -y curl git wget openssh-server sudo make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel centos-release-scl devtoolset-8 llvm-toolset-7 && yum clean all + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN wget -qO- "https://cmake.org/files/v3.15/cmake-3.15.1-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /usr/local + +RUN /usr/bin/ssh-keygen -A +RUN useradd jenkins-build + +RUN echo $'\n\ + export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n\ + source scl_source enable devtoolset-8 llvm-toolset-7\n'\ + >> ~/.bash_profile + +RUN mkdir /rpmbuild && chmod 777 /rpmbuild + +CMD ["/usr/sbin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.centos7-i386 b/dockerbuild/Dockerfile.centos7-i386 new file mode 100644 index 00000000..f7ee9a0c --- /dev/null +++ b/dockerbuild/Dockerfile.centos7-i386 @@ -0,0 +1,22 @@ +FROM centos:7 + +ARG go_pkg_url + +RUN yum install -y curl git wget openssh-server sudo make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel && yum clean all + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN /usr/bin/ssh-keygen -A + +RUN useradd jenkins-build + +RUN echo $'\n\ + export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ + >> ~/.bash_profile + +RUN mkdir /rpmbuild && chmod 777 /rpmbuild + +CMD ["/usr/sbin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.centos8 b/dockerbuild/Dockerfile.centos8 new file mode 100644 index 00000000..106ab5b4 --- /dev/null +++ b/dockerbuild/Dockerfile.centos8 @@ -0,0 +1,25 @@ +FROM centos:8 + +ARG go_pkg_url + +RUN yum install -y epel-release +RUN yum install -y curl git wget openssh-server sudo make rpmdevtools clang gcc-c++ ruby ruby-devel && yum clean all + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN wget -qO- "https://cmake.org/files/v3.15/cmake-3.15.1-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /usr/local + +RUN /usr/bin/ssh-keygen -A +RUN useradd jenkins-build + +RUN echo $'\n\ + export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n\ + source scl_source enable devtoolset-8 llvm-toolset-7\n'\ + >> ~/.bash_profile + +RUN mkdir /rpmbuild && chmod 777 /rpmbuild + +CMD ["/usr/sbin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.clefos-s390x b/dockerbuild/Dockerfile.clefos-s390x new file mode 100644 index 00000000..135f70ab --- /dev/null +++ b/dockerbuild/Dockerfile.clefos-s390x @@ -0,0 +1,20 @@ +FROM s390x/clefos:7 + +ARG go_pkg_url + +RUN yum install -y curl git wget openssh-server sudo make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel && yum clean all + +RUN curl -s $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN /usr/bin/ssh-keygen -A + +RUN echo $'\n\ + export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ + >> ~/.bash_profile + +RUN mkdir /rpmbuild && chmod 777 /rpmbuild + +CMD ["/usr/sbin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.debian-bullseye b/dockerbuild/Dockerfile.debian-bullseye new file mode 100644 index 00000000..518a08ae --- /dev/null +++ b/dockerbuild/Dockerfile.debian-bullseye @@ -0,0 +1,15 @@ +FROM debian:bullseye-20191224 + +ARG go_pkg_url + +RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.debian-buster b/dockerbuild/Dockerfile.debian-buster new file mode 100644 index 00000000..6504178b --- /dev/null +++ b/dockerbuild/Dockerfile.debian-buster @@ -0,0 +1,15 @@ +FROM debian:buster-20191224 + +ARG go_pkg_url + +RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.debian-jessie b/dockerbuild/Dockerfile.debian-jessie new file mode 100644 index 00000000..31b0a904 --- /dev/null +++ b/dockerbuild/Dockerfile.debian-jessie @@ -0,0 +1,15 @@ +FROM debian:jessie-20191224 + +ARG go_pkg_url + +RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.debian-sid b/dockerbuild/Dockerfile.debian-sid new file mode 100644 index 00000000..5fde10d5 --- /dev/null +++ b/dockerbuild/Dockerfile.debian-sid @@ -0,0 +1,15 @@ +FROM debian:sid-20191224 + +ARG go_pkg_url + +RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.debian-stretch b/dockerbuild/Dockerfile.debian-stretch new file mode 100644 index 00000000..76342fb8 --- /dev/null +++ b/dockerbuild/Dockerfile.debian-stretch @@ -0,0 +1,15 @@ +FROM debian:stretch-20191224 + +ARG go_pkg_url + +RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.debian-wheezy b/dockerbuild/Dockerfile.debian-wheezy new file mode 100644 index 00000000..7322959e --- /dev/null +++ b/dockerbuild/Dockerfile.debian-wheezy @@ -0,0 +1,23 @@ +FROM debian:wheezy-20190228 + +ARG go_pkg_url + +RUN echo "deb http://archive.debian.org/debian/ wheezy contrib main non-free" > /etc/apt/sources.list && \ + echo "deb-src http://archive.debian.org/debian/ wheezy contrib main non-free" >> /etc/apt/sources.list && \ + apt-get update && apt-get install -y apt-utils && \ + apt-get install -y --force-yes \ + curl gcc make sudo expect gnupg fakeroot perl-base=5.14.2-21+deb7u3 perl \ + libc-bin=2.13-38+deb7u10 libc6=2.13-38+deb7u10 libc6-dev build-essential \ + cdbs devscripts equivs automake autoconf libtool libaudit-dev selinux-basics \ + libdb5.1=5.1.29-5 libdb5.1-dev libssl1.0.0=1.0.1e-2+deb7u20 procps gawk libsigsegv2 \ + curl ca-certificates devscripts + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.kali-rolling b/dockerbuild/Dockerfile.kali-rolling new file mode 100644 index 00000000..2825dffe --- /dev/null +++ b/dockerbuild/Dockerfile.kali-rolling @@ -0,0 +1,15 @@ +FROM kalilinux/kali-rolling:latest + +ARG go_pkg_url + +RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.ubuntu-bionic b/dockerbuild/Dockerfile.ubuntu-bionic new file mode 100644 index 00000000..2bbc5b02 --- /dev/null +++ b/dockerbuild/Dockerfile.ubuntu-bionic @@ -0,0 +1,15 @@ +FROM ubuntu:bionic-20200112 + +ARG go_pkg_url + +RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.ubuntu-eoan b/dockerbuild/Dockerfile.ubuntu-eoan new file mode 100644 index 00000000..0fd5e33c --- /dev/null +++ b/dockerbuild/Dockerfile.ubuntu-eoan @@ -0,0 +1,15 @@ +FROM ubuntu:eoan-20200114 + +ARG go_pkg_url + +RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.ubuntu-trusty b/dockerbuild/Dockerfile.ubuntu-trusty new file mode 100644 index 00000000..52a80c94 --- /dev/null +++ b/dockerbuild/Dockerfile.ubuntu-trusty @@ -0,0 +1,15 @@ +FROM ubuntu:trusty-20191217 + +ARG go_pkg_url + +RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Dockerfile.ubuntu-xenial b/dockerbuild/Dockerfile.ubuntu-xenial new file mode 100644 index 00000000..bda74f47 --- /dev/null +++ b/dockerbuild/Dockerfile.ubuntu-xenial @@ -0,0 +1,15 @@ +FROM ubuntu:xenial-20200114 + +ARG go_pkg_url + +RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd + +RUN curl -s -k $go_pkg_url -o go.tar.gz && \ + tar -C /usr/local -xzf go.tar.gz && \ + rm go.tar.gz + +RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build +RUN chmod 777 /home + +CMD ["/usr/bin/sshd", "-D"] + diff --git a/dockerbuild/Makefile b/dockerbuild/Makefile new file mode 100644 index 00000000..543d45d5 --- /dev/null +++ b/dockerbuild/Makefile @@ -0,0 +1,108 @@ +.PHONY: all + +all: alpine centos debian ubuntu kali-rolling + +alpine: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.alpine . -t ztbuild/alpine-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.alpine . -t ztbuild/alpine-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.alpine . -t ztbuild/alpine-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.alpine . -t ztbuild/alpine-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.alpine . -t ztbuild/alpine-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.alpine . -t ztbuild/alpine-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.alpine . -t ztbuild/alpine-s390x --load + +centos: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.centos7 . -t ztbuild/centos7-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.centos7-i386 . -t ztbuild/centos7-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.centos6 . -t ztbuild/centos6-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.centos6-i386 . -t ztbuild/centos6-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.centos8 . -t ztbuild/centos8-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.centos8 . -t ztbuild/centos8-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.centos8 . -t ztbuild/centos8-ppc64le --load + +debian: debian-wheezy debian-jessie debian-buster debian-stretch debian-bullseye debian-sid + +debian-wheezy: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-i386 --load + +debian-jessie: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-i386 --load + +debian-buster: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-buster . -t ztbuild/debian-buster-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-buster . -t ztbuild/debian-buster-s390x --load + +debian-stretch: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-s390x --load + +debian-bullseye: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-s390x --load + +debian-sid: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-armel --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-sid . -t ztbuild/debian-sid-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-sid . -t ztbuild/debian-sid-s390x --load + +ubuntu: ubuntu-trusty ubuntu-xenial ubuntu-bionic ubuntu-eoan + +ubuntu-trusty: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-ppc64le --load + +ubuntu-xenial: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-s390x --load + +ubuntu-bionic: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-s390x --load + +ubuntu-eoan: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-amd64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-arm64 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-armhf --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-i386 --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-ppc64le --load + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-s390x --load + +kali-rolling: + @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.kali-rolling . -t ztbuild/kali-rolling-amd64 --load + diff --git a/dockerbuild/authorized_keys b/dockerbuild/authorized_keys new file mode 100644 index 00000000..0dd35c7b --- /dev/null +++ b/dockerbuild/authorized_keys @@ -0,0 +1,2 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8hgysbj2Luu3aN/Ya2wr4Y9LpUGqWWfn3k+UhIwOIE/Kd7/YpLjxHpseUA1hLnj9kHFShH8eiqoY0S6EDIYrTUwbXMMu8454lX/LcJOCJ9RlSeMMf7vpkxcI7cVRgOA430a3FR7M0Q8vKlyJzxxAEjMIxMyuVyinknfanNt+sQFiDUvOXoacqgZAHBWMlO7wOPyHWHNOzy7g8N0dHiJveKZqX/UUwuqJuS6UBq7MBMSU6TcMvJwHr+AbNvfyIUWCqlTByqFL9cmviRbIvQanxoRxi/5fVUGhtVBXUYvbCdFxDw5W2Svo9fDMm4Z5xWAD7rY1J3AM15RVyRTTtYvgD + diff --git a/dockerbuild/pipelint.sh b/dockerbuild/pipelint.sh new file mode 100644 index 00000000..7fbd0de8 --- /dev/null +++ b/dockerbuild/pipelint.sh @@ -0,0 +1,13 @@ +# curl (REST API) +# User +JENKINS_USER=grant + +# Api key from "/me/configure" on my Jenkins instance +JENKINS_USER_KEY=11edf2d49321321119712c46c6349eaad7 + +# Url for my local Jenkins instance. +JENKINS_URL=http://$JENKINS_USER:$JENKINS_USER_KEY@jenkins.int.zerotier.com + +# JENKINS_CRUMB is needed if your Jenkins master has CRSF protection enabled (which it should) +JENKINS_CRUMB=`curl "$JENKINS_URL/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)"` +curl -X POST -H $JENKINS_CRUMB -F "jenkinsfile=, Grant Limberg + +ARG git_branch=master + +RUN yum update -y +RUN yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm +RUN yum -y install epel-release && yum -y update && yum clean all +RUN yum groupinstall -y "Development Tools" +RUN yum install -y bash postgresql10 postgresql10-devel libpqxx-devel glibc-static libstdc++-static clang jemalloc jemalloc-devel + +# RUN git clone http://git.int.zerotier.com/zerotier/ZeroTierOne.git +# RUN if [ "$git_branch" != "master" ]; then cd ZeroTierOne && git checkout -b $git_branch origin/$git_branch; fi +ADD . /ZeroTierOne +RUN cd ZeroTierOne && make clean && make central-controller + +FROM centos:7 +RUN yum install -y yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm && yum -y install epel-release && yum -y update && yum clean all +RUN yum install -y jemalloc jemalloc-devel postgresql10 + +COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one +RUN chmod a+x /usr/local/bin/zerotier-one + +ADD ext/central-controller-docker/main.sh / +RUN chmod a+x /main.sh + +ENTRYPOINT /main.sh diff --git a/ext/central-controller-docker/README.md b/ext/central-controller-docker/README.md new file mode 100644 index 00000000..a954b1c3 --- /dev/null +++ b/ext/central-controller-docker/README.md @@ -0,0 +1,3 @@ +# ZeroTier Central Controller Docker Image + +Dockerfile & startup script for use with [ZeroTier Central](https://my.zerotier.com). Not intended for public use. diff --git a/docker/main.sh b/ext/central-controller-docker/main.sh old mode 100644 new mode 100755 similarity index 100% rename from docker/main.sh rename to ext/central-controller-docker/main.sh diff --git a/ext/hiredis-vip-0.3.0/.gitignore b/ext/hiredis-vip-0.3.0/.gitignore new file mode 100644 index 00000000..c44b5c53 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/.gitignore @@ -0,0 +1,7 @@ +/hiredis-test +/examples/hiredis-example* +/*.o +/*.so +/*.dylib +/*.a +/*.pc diff --git a/ext/hiredis-vip-0.3.0/.travis.yml b/ext/hiredis-vip-0.3.0/.travis.yml new file mode 100644 index 00000000..1df63b0b --- /dev/null +++ b/ext/hiredis-vip-0.3.0/.travis.yml @@ -0,0 +1,16 @@ +language: c +compiler: + - gcc + - clang + +env: + - CFLAGS="-Werror" + - PRE="valgrind --track-origins=yes --leak-check=full" + - TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror" + - TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" + +install: + - sudo apt-get update -qq + - sudo apt-get install libc6-dbg libc6-dev libc6-i686:i386 libc6-dev-i386 libc6-dbg:i386 valgrind -y + +script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example diff --git a/ext/hiredis-vip-0.3.0/CHANGELOG.md b/ext/hiredis-vip-0.3.0/CHANGELOG.md new file mode 100644 index 00000000..db304b6a --- /dev/null +++ b/ext/hiredis-vip-0.3.0/CHANGELOG.md @@ -0,0 +1,16 @@ +### 0.3.0 - Dec 07, 2016 + +* Support redisClustervCommand, redisClustervAppendCommand and redisClustervAsyncCommand api. (deep011) +* Add flags HIRCLUSTER_FLAG_ADD_OPENSLOT and HIRCLUSTER_FLAG_ROUTE_USE_SLOTS. (deep011) +* Support redisClusterCommandArgv related api. (deep011) +* Fix some serious bugs. (deep011) + +### 0.2.1 - Nov 24, 2015 + +This release support redis cluster api. + +* Add hiredis 0.3.1. (deep011) +* Support cluster synchronous API. (deep011) +* Support multi-key command(mget/mset/del) for redis cluster. (deep011) +* Support cluster pipelining. (deep011) +* Support cluster asynchronous API. (deep011) diff --git a/ext/hiredis-vip-0.3.0/COPYING b/ext/hiredis-vip-0.3.0/COPYING new file mode 100644 index 00000000..a5fc9739 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/COPYING @@ -0,0 +1,29 @@ +Copyright (c) 2009-2011, Salvatore Sanfilippo +Copyright (c) 2010-2011, Pieter Noordhuis + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of Redis nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ext/hiredis-vip-0.3.0/Makefile b/ext/hiredis-vip-0.3.0/Makefile new file mode 100644 index 00000000..58494bfc --- /dev/null +++ b/ext/hiredis-vip-0.3.0/Makefile @@ -0,0 +1,205 @@ +# Hiredis Makefile +# Copyright (C) 2010-2011 Salvatore Sanfilippo +# Copyright (C) 2010-2011 Pieter Noordhuis +# This file is released under the BSD license, see the COPYING file + +OBJ=net.o hiredis.o sds.o async.o read.o hiarray.o hiutil.o command.o crc16.o adlist.o hircluster.o +EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib +TESTS=hiredis-test +LIBNAME=libhiredis_vip +PKGCONFNAME=hiredis.pc + +HIREDIS_VIP_MAJOR=$(shell grep HIREDIS_VIP_MAJOR hircluster.h | awk '{print $$3}') +HIREDIS_VIP_MINOR=$(shell grep HIREDIS_VIP_MINOR hircluster.h | awk '{print $$3}') +HIREDIS_VIP_PATCH=$(shell grep HIREDIS_VIP_PATCH hircluster.h | awk '{print $$3}') + +# Installation related variables and target +PREFIX?=/usr/local +INCLUDE_PATH?=include/hiredis-vip +LIBRARY_PATH?=lib +PKGCONF_PATH?=pkgconfig +INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH) +INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) +INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH) + +# redis-server configuration used for testing +REDIS_PORT=56379 +REDIS_SERVER=redis-server +define REDIS_TEST_CONFIG + daemonize yes + pidfile /tmp/hiredis-test-redis.pid + port $(REDIS_PORT) + bind 127.0.0.1 + unixsocket /tmp/hiredis-test-redis.sock +endef +export REDIS_TEST_CONFIG + +# Fallback to gcc when $CC is not in $PATH. +CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') +OPTIMIZATION?=-O3 +WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings +DEBUG?= -g -ggdb +REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH) +REAL_LDFLAGS=$(LDFLAGS) $(ARCH) + +DYLIBSUFFIX=so +STLIBSUFFIX=a +DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_VIP_MAJOR).$(HIREDIS_VIP_MINOR) +DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_VIP_MAJOR) +DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) +DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) +STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) +STLIB_MAKE_CMD=ar rcs $(STLIBNAME) + +# Platform-specific overrides +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +ifeq ($(uname_S),SunOS) + REAL_LDFLAGS+= -ldl -lnsl -lsocket + DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) + INSTALL= cp -r +endif +ifeq ($(uname_S),Darwin) + DYLIBSUFFIX=dylib + DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_VIP_MAJOR).$(HIREDIS_VIP_MINOR).$(DYLIBSUFFIX) + DYLIB_MAJOR_NAME=$(LIBNAME).$(HIREDIS_VIP_MAJOR).$(DYLIBSUFFIX) + DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) +endif + +all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) + +# Deps (use make dep to generate this) + +adlist.o: adlist.c adlist.h hiutil.h +async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h +command.o: command.c command.h hiredis.h read.h sds.h adlist.h hiutil.h hiarray.h +crc16.o: crc16.c hiutil.h +dict.o: dict.c fmacros.h dict.h +hiarray.o: hiarray.c hiarray.h hiutil.h +hircluster.o: hircluster.c fmacros.h hircluster.h hiredis.h read.h sds.h adlist.h hiarray.h hiutil.h async.h command.h dict.c dict.h +hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h +hiutil.o: hiutil.c hiutil.h +net.o: net.c fmacros.h net.h hiredis.h read.h sds.h +read.o: read.c fmacros.h read.h sds.h +sds.o: sds.c sds.h +test.o: test.c fmacros.h hiredis.h read.h sds.h net.h + +$(DYLIBNAME): $(OBJ) + $(DYLIB_MAKE_CMD) $(OBJ) + +$(STLIBNAME): $(OBJ) + $(STLIB_MAKE_CMD) $(OBJ) + +dynamic: $(DYLIBNAME) +static: $(STLIBNAME) + +# Binaries: +hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME) + +hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME) + +hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) $(shell pkg-config --cflags --libs glib-2.0) -I. $< $(STLIBNAME) + +ifndef AE_DIR +hiredis-example-ae: + @echo "Please specify AE_DIR (e.g. /src)" + @false +else +hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME) +endif + +ifndef LIBUV_DIR +hiredis-example-libuv: + @echo "Please specify LIBUV_DIR (e.g. ../libuv/)" + @false +else +hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread $(STLIBNAME) +endif + +hiredis-example: examples/example.c $(STLIBNAME) + $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME) + +examples: $(EXAMPLES) + +hiredis-test: test.o $(STLIBNAME) + +hiredis-%: %.o $(STLIBNAME) + $(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME) + +test: hiredis-test + ./hiredis-test + +check: hiredis-test + @echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) - + $(PRE) ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \ + ( kill `cat /tmp/hiredis-test-redis.pid` && false ) + kill `cat /tmp/hiredis-test-redis.pid` + +.c.o: + $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< + +clean: + rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov + +dep: + $(CC) -MM *.c + +ifeq ($(uname_S),SunOS) + INSTALL?= cp -r +endif + +INSTALL?= cp -a + +$(PKGCONFNAME): hiredis.h + @echo "Generating $@ for pkgconfig..." + @echo prefix=$(PREFIX) > $@ + @echo exec_prefix=\$${prefix} >> $@ + @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@ + @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ + @echo >> $@ + @echo Name: hiredis >> $@ + @echo Description: Minimalistic C client library for Redis. >> $@ + @echo Version: $(HIREDIS_VIP_MAJOR).$(HIREDIS_VIP_MINOR).$(HIREDIS_VIP_PATCH) >> $@ + @echo Libs: -L\$${libdir} -lhiredis >> $@ + @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ + +install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) + mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) + $(INSTALL) hiredis.h async.h read.h sds.h hiutil.h hiarray.h dict.h dict.c adlist.h fmacros.h hircluster.h adapters $(INSTALL_INCLUDE_PATH) + $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME) + $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) + mkdir -p $(INSTALL_PKGCONF_PATH) + $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) + +32bit: + @echo "" + @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" + @echo "" + $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" + +32bit-vars: + $(eval CFLAGS=-m32) + $(eval LDFLAGS=-m32) + +gprof: + $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" + +gcov: + $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" + +coverage: gcov + make check + mkdir -p tmp/lcov + lcov -d . -c -o tmp/lcov/hiredis.info + genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info + +noopt: + $(MAKE) OPTIMIZATION="" + +.PHONY: all test check clean dep install 32bit gprof gcov noopt diff --git a/ext/hiredis-vip-0.3.0/README.md b/ext/hiredis-vip-0.3.0/README.md new file mode 100644 index 00000000..89741939 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/README.md @@ -0,0 +1,255 @@ + +# HIREDIS-VIP + +Hiredis-vip is a C client library for the [Redis](http://redis.io/) database. + +Hiredis-vip supported redis cluster. + +Hiredis-vip fully contained and based on [Hiredis](https://github.com/redis/hiredis) . + +## CLUSTER SUPPORT + +### FEATURES: + +* **`SUPPORT REDIS CLUSTER`**: + * Connect to redis cluster and run commands. + +* **`SUPPORT MULTI-KEY COMMAND`**: + * Support `MSET`, `MGET` and `DEL`. + +* **`SUPPORT PIPELING`**: + * Support redis pipeline and can contain multi-key command like above. + +* **`SUPPORT Asynchronous API`**: + * User can run commands with asynchronous mode. + +### CLUSTER API: + +```c +redisClusterContext *redisClusterConnect(const char *addrs, int flags); +redisClusterContext *redisClusterConnectWithTimeout(const char *addrs, const struct timeval tv, int flags); +redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags); +void redisClusterFree(redisClusterContext *cc); +void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); +void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len); +void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap); +void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); +void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); +redisContext *ctx_get_by_node(struct cluster_node *node, const struct timeval *timeout, int flags); +int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, int len); +int redisClustervAppendCommand(redisClusterContext *cc, const char *format, va_list ap); +int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); +int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); +int redisClusterGetReply(redisClusterContext *cc, void **reply); +void redisClusterReset(redisClusterContext *cc); + +redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags); +int redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn); +int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); +int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, char *cmd, int len); +int redisClustervAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap); +int redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, ...); +int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); + +void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); +void redisClusterAsyncFree(redisClusterAsyncContext *acc); +``` + +## Quick usage + +If you want used but not read the follow, please reference the examples: +https://github.com/vipshop/hiredis-vip/wiki + +## Cluster synchronous API + +To consume the synchronous API, there are only a few function calls that need to be introduced: + +```c +redisClusterContext *redisClusterConnect(const char *addrs, int flags); +void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); +void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); +void redisClusterFree(redisClusterContext *cc); +``` + +### Cluster connecting + +The function `redisClusterConnect` is used to create a so-called `redisClusterContext`. The +context is where Hiredis-vip Cluster holds state for connections. The `redisClusterContext` +struct has an integer `err` field that is non-zero when the connection is in +an error state. The field `errstr` will contain a string with a description of +the error. +After trying to connect to Redis using `redisClusterContext` you should +check the `err` field to see if establishing the connection was successful: +```c +redisClusterContext *cc = redisClusterConnect("127.0.0.1:6379", HIRCLUSTER_FLAG_NULL); +if (cc != NULL && cc->err) { + printf("Error: %s\n", cc->errstr); + // handle error +} +``` + +### Cluster sending commands + +The next that will be introduced is `redisClusterCommand`. +This function takes a format similar to printf. In the simplest form, +it is used like this: +```c +reply = redisClusterCommand(clustercontext, "SET foo bar"); +``` + +The specifier `%s` interpolates a string in the command, and uses `strlen` to +determine the length of the string: +```c +reply = redisClusterCommand(clustercontext, "SET foo %s", value); +``` +Internally, Hiredis-vip splits the command in different arguments and will +convert it to the protocol used to communicate with Redis. +One or more spaces separates arguments, so you can use the specifiers +anywhere in an argument: +```c +reply = redisClusterCommand(clustercontext, "SET key:%s %s", myid, value); +``` + +### Cluster multi-key commands + +Hiredis-vip supports mget/mset/del multi-key commands. +Those multi-key commands is highly effective. +Millions of keys in one mget command just used several seconds. + +Example: +```c +reply = redisClusterCommand(clustercontext, "mget %s %s %s %s", key1, key2, key3, key4); +``` + +### Cluster cleaning up + +To disconnect and free the context the following function can be used: +```c +void redisClusterFree(redisClusterContext *cc); +``` +This function immediately closes the socket and then frees the allocations done in +creating the context. + +### Cluster pipelining + +The function `redisClusterGetReply` is exported as part of the Hiredis API and can be used +when a reply is expected on the socket. To pipeline commands, the only things that needs +to be done is filling up the output buffer. For this cause, two commands can be used that +are identical to the `redisClusterCommand` family, apart from not returning a reply: +```c +int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); +int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv); +``` +After calling either function one or more times, `redisClusterGetReply` can be used to receive the +subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where +the latter means an error occurred while reading a reply. Just as with the other commands, +the `err` field in the context can be used to find out what the cause of this error is. +```c +void redisClusterReset(redisClusterContext *cc); +``` +Warning: You must call `redisClusterReset` function after one pipelining anyway. + +The following examples shows a simple cluster pipeline: +```c +redisReply *reply; +redisClusterAppendCommand(clusterContext,"SET foo bar"); +redisClusterAppendCommand(clusterContext,"GET foo"); +redisClusterGetReply(clusterContext,&reply); // reply for SET +freeReplyObject(reply); +redisClusterGetReply(clusterContext,&reply); // reply for GET +freeReplyObject(reply); +redisClusterReset(clusterContext); +``` + +## Cluster asynchronous API + +Hiredis-vip comes with an cluster asynchronous API that works easily with any event library. +Now we just support and test for libevent and redis ae, if you need for other event libraries, +please contact with us, and we will support it quickly. + +### Connecting + +The function `redisAsyncConnect` can be used to establish a non-blocking connection to +Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field +should be checked after creation to see if there were errors creating the connection. +Because the connection that will be created is non-blocking, the kernel is not able to +instantly return if the specified host and port is able to accept a connection. +```c +redisClusterAsyncContext *acc = redisClusterAsyncConnect("127.0.0.1:6379", HIRCLUSTER_FLAG_NULL); +if (acc->err) { + printf("Error: %s\n", acc->errstr); + // handle error +} +``` + +The cluster asynchronous context can hold a disconnect callback function that is called when the +connection is disconnected (either because of an error or per user request). This function should +have the following prototype: +```c +void(const redisAsyncContext *c, int status); +``` +On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the +user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err` +field in the context can be accessed to find out the cause of the error. + +You not need to reconnect in the disconnect callback, hiredis-vip will reconnect this connection itself +when commands come to this redis node. + +Setting the disconnect callback can only be done once per context. For subsequent calls it will +return `REDIS_ERR`. The function to set the disconnect callback has the following prototype: +```c +int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); +``` +### Sending commands and their callbacks + +In an cluster asynchronous context, commands are automatically pipelined due to the nature of an event loop. +Therefore, unlike the cluster synchronous API, there is only a single way to send commands. +Because commands are sent to Redis cluster asynchronously, issuing a command requires a callback function +that is called when the reply is received. Reply callbacks should have the following prototype: +```c +void(redisClusterAsyncContext *acc, void *reply, void *privdata); +``` +The `privdata` argument can be used to curry arbitrary data to the callback from the point where +the command is initially queued for execution. + +The functions that can be used to issue commands in an asynchronous context are: +```c +int redisClusterAsyncCommand( + redisClusterAsyncContext *acc, + redisClusterCallbackFn *fn, + void *privdata, const char *format, ...); +``` +This function work like their blocking counterparts. The return value is `REDIS_OK` when the command +was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection +is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is +returned on calls to the `redisClusterAsyncCommand` family. + +If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback +for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only +valid for the duration of the callback. + +All pending callbacks are called with a `NULL` reply when the context encountered an error. + +### Disconnecting + +An cluster asynchronous connection can be terminated using: +```c +void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); +``` +When this function is called, the connection is **not** immediately terminated. Instead, new +commands are no longer accepted and the connection is only terminated when all pending commands +have been written to the socket, their respective replies have been read and their respective +callbacks have been executed. After this, the disconnection callback is executed with the +`REDIS_OK` status and the context object is freed. + +### Hooking it up to event library *X* + +There are a few hooks that need to be set on the cluster context object after it is created. +See the `adapters/` directory for bindings to *ae* and *libevent*. + +## AUTHORS + +Hiredis-vip was maintained and used at vipshop(https://github.com/vipshop). +The redis client library part in hiredis-vip is same as hiredis(https://github.com/redis/hiredis). +The redis cluster client library part in hiredis-vip is written by deep(https://github.com/deep011). +Hiredis-vip is released under the BSD license. diff --git a/ext/hiredis-vip-0.3.0/adapters/ae.h b/ext/hiredis-vip-0.3.0/adapters/ae.h new file mode 100644 index 00000000..f861cf28 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adapters/ae.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_AE_H__ +#define __HIREDIS_AE_H__ +#include +#include +#include "../hiredis.h" +#include "../async.h" + +#if 1 //shenzheng 2015-11-5 redis cluster +#include "../hircluster.h" +#endif //shenzheng 2015-11-5 redis cluster + +typedef struct redisAeEvents { + redisAsyncContext *context; + aeEventLoop *loop; + int fd; + int reading, writing; +} redisAeEvents; + +static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { + ((void)el); ((void)fd); ((void)mask); + + redisAeEvents *e = (redisAeEvents*)privdata; + redisAsyncHandleRead(e->context); +} + +static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { + ((void)el); ((void)fd); ((void)mask); + + redisAeEvents *e = (redisAeEvents*)privdata; + redisAsyncHandleWrite(e->context); +} + +static void redisAeAddRead(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (!e->reading) { + e->reading = 1; + aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); + } +} + +static void redisAeDelRead(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (e->reading) { + e->reading = 0; + aeDeleteFileEvent(loop,e->fd,AE_READABLE); + } +} + +static void redisAeAddWrite(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (!e->writing) { + e->writing = 1; + aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); + } +} + +static void redisAeDelWrite(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (e->writing) { + e->writing = 0; + aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); + } +} + +static void redisAeCleanup(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + redisAeDelRead(privdata); + redisAeDelWrite(privdata); + free(e); +} + +static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisAeEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisAeEvents*)malloc(sizeof(*e)); + e->context = ac; + e->loop = loop; + e->fd = c->fd; + e->reading = e->writing = 0; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisAeAddRead; + ac->ev.delRead = redisAeDelRead; + ac->ev.addWrite = redisAeAddWrite; + ac->ev.delWrite = redisAeDelWrite; + ac->ev.cleanup = redisAeCleanup; + ac->ev.data = e; + + return REDIS_OK; +} + +#if 1 //shenzheng 2015-11-5 redis cluster + +static int redisAeAttach_link(redisAsyncContext *ac, void *base) +{ + redisAeAttach((aeEventLoop *)base, ac); +} + +static int redisClusterAeAttach(aeEventLoop *loop, redisClusterAsyncContext *acc) { + + if(acc == NULL || loop == NULL) + { + return REDIS_ERR; + } + + acc->adapter = loop; + acc->attach_fn = redisAeAttach_link; + + return REDIS_OK; +} + +#endif //shenzheng 2015-11-5 redis cluster + +#endif diff --git a/ext/hiredis-vip-0.3.0/adapters/glib.h b/ext/hiredis-vip-0.3.0/adapters/glib.h new file mode 100644 index 00000000..e13eee73 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adapters/glib.h @@ -0,0 +1,153 @@ +#ifndef __HIREDIS_GLIB_H__ +#define __HIREDIS_GLIB_H__ + +#include + +#include "../hiredis.h" +#include "../async.h" + +typedef struct +{ + GSource source; + redisAsyncContext *ac; + GPollFD poll_fd; +} RedisSource; + +static void +redis_source_add_read (gpointer data) +{ + RedisSource *source = data; + g_return_if_fail(source); + source->poll_fd.events |= G_IO_IN; + g_main_context_wakeup(g_source_get_context(data)); +} + +static void +redis_source_del_read (gpointer data) +{ + RedisSource *source = data; + g_return_if_fail(source); + source->poll_fd.events &= ~G_IO_IN; + g_main_context_wakeup(g_source_get_context(data)); +} + +static void +redis_source_add_write (gpointer data) +{ + RedisSource *source = data; + g_return_if_fail(source); + source->poll_fd.events |= G_IO_OUT; + g_main_context_wakeup(g_source_get_context(data)); +} + +static void +redis_source_del_write (gpointer data) +{ + RedisSource *source = data; + g_return_if_fail(source); + source->poll_fd.events &= ~G_IO_OUT; + g_main_context_wakeup(g_source_get_context(data)); +} + +static void +redis_source_cleanup (gpointer data) +{ + RedisSource *source = data; + + g_return_if_fail(source); + + redis_source_del_read(source); + redis_source_del_write(source); + /* + * It is not our responsibility to remove ourself from the + * current main loop. However, we will remove the GPollFD. + */ + if (source->poll_fd.fd >= 0) { + g_source_remove_poll(data, &source->poll_fd); + source->poll_fd.fd = -1; + } +} + +static gboolean +redis_source_prepare (GSource *source, + gint *timeout_) +{ + RedisSource *redis = (RedisSource *)source; + *timeout_ = -1; + return !!(redis->poll_fd.events & redis->poll_fd.revents); +} + +static gboolean +redis_source_check (GSource *source) +{ + RedisSource *redis = (RedisSource *)source; + return !!(redis->poll_fd.events & redis->poll_fd.revents); +} + +static gboolean +redis_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + RedisSource *redis = (RedisSource *)source; + + if ((redis->poll_fd.revents & G_IO_OUT)) { + redisAsyncHandleWrite(redis->ac); + redis->poll_fd.revents &= ~G_IO_OUT; + } + + if ((redis->poll_fd.revents & G_IO_IN)) { + redisAsyncHandleRead(redis->ac); + redis->poll_fd.revents &= ~G_IO_IN; + } + + if (callback) { + return callback(user_data); + } + + return TRUE; +} + +static void +redis_source_finalize (GSource *source) +{ + RedisSource *redis = (RedisSource *)source; + + if (redis->poll_fd.fd >= 0) { + g_source_remove_poll(source, &redis->poll_fd); + redis->poll_fd.fd = -1; + } +} + +static GSource * +redis_source_new (redisAsyncContext *ac) +{ + static GSourceFuncs source_funcs = { + .prepare = redis_source_prepare, + .check = redis_source_check, + .dispatch = redis_source_dispatch, + .finalize = redis_source_finalize, + }; + redisContext *c = &ac->c; + RedisSource *source; + + g_return_val_if_fail(ac != NULL, NULL); + + source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); + source->ac = ac; + source->poll_fd.fd = c->fd; + source->poll_fd.events = 0; + source->poll_fd.revents = 0; + g_source_add_poll((GSource *)source, &source->poll_fd); + + ac->ev.addRead = redis_source_add_read; + ac->ev.delRead = redis_source_del_read; + ac->ev.addWrite = redis_source_add_write; + ac->ev.delWrite = redis_source_del_write; + ac->ev.cleanup = redis_source_cleanup; + ac->ev.data = source; + + return (GSource *)source; +} + +#endif /* __HIREDIS_GLIB_H__ */ diff --git a/ext/hiredis-vip-0.3.0/adapters/libev.h b/ext/hiredis-vip-0.3.0/adapters/libev.h new file mode 100644 index 00000000..2bf8d521 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adapters/libev.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_LIBEV_H__ +#define __HIREDIS_LIBEV_H__ +#include +#include +#include +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisLibevEvents { + redisAsyncContext *context; + struct ev_loop *loop; + int reading, writing; + ev_io rev, wev; +} redisLibevEvents; + +static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { +#if EV_MULTIPLICITY + ((void)loop); +#endif + ((void)revents); + + redisLibevEvents *e = (redisLibevEvents*)watcher->data; + redisAsyncHandleRead(e->context); +} + +static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { +#if EV_MULTIPLICITY + ((void)loop); +#endif + ((void)revents); + + redisLibevEvents *e = (redisLibevEvents*)watcher->data; + redisAsyncHandleWrite(e->context); +} + +static void redisLibevAddRead(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (!e->reading) { + e->reading = 1; + ev_io_start(EV_A_ &e->rev); + } +} + +static void redisLibevDelRead(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (e->reading) { + e->reading = 0; + ev_io_stop(EV_A_ &e->rev); + } +} + +static void redisLibevAddWrite(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (!e->writing) { + e->writing = 1; + ev_io_start(EV_A_ &e->wev); + } +} + +static void redisLibevDelWrite(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + struct ev_loop *loop = e->loop; + ((void)loop); + if (e->writing) { + e->writing = 0; + ev_io_stop(EV_A_ &e->wev); + } +} + +static void redisLibevCleanup(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + redisLibevDelRead(privdata); + redisLibevDelWrite(privdata); + free(e); +} + +static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisLibevEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibevEvents*)malloc(sizeof(*e)); + e->context = ac; +#if EV_MULTIPLICITY + e->loop = loop; +#else + e->loop = NULL; +#endif + e->reading = e->writing = 0; + e->rev.data = e; + e->wev.data = e; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibevAddRead; + ac->ev.delRead = redisLibevDelRead; + ac->ev.addWrite = redisLibevAddWrite; + ac->ev.delWrite = redisLibevDelWrite; + ac->ev.cleanup = redisLibevCleanup; + ac->ev.data = e; + + /* Initialize read/write events */ + ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); + ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); + return REDIS_OK; +} + +#endif diff --git a/ext/hiredis-vip-0.3.0/adapters/libevent.h b/ext/hiredis-vip-0.3.0/adapters/libevent.h new file mode 100644 index 00000000..6bc911c7 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adapters/libevent.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_LIBEVENT_H__ +#define __HIREDIS_LIBEVENT_H__ +#include +#include "../hiredis.h" +#include "../async.h" + +#if 1 //shenzheng 2015-9-21 redis cluster +#include "../hircluster.h" +#endif //shenzheng 2015-9-21 redis cluster + +typedef struct redisLibeventEvents { + redisAsyncContext *context; + struct event rev, wev; +} redisLibeventEvents; + +static void redisLibeventReadEvent(int fd, short event, void *arg) { + ((void)fd); ((void)event); + redisLibeventEvents *e = (redisLibeventEvents*)arg; + redisAsyncHandleRead(e->context); +} + +static void redisLibeventWriteEvent(int fd, short event, void *arg) { + ((void)fd); ((void)event); + redisLibeventEvents *e = (redisLibeventEvents*)arg; + redisAsyncHandleWrite(e->context); +} + +static void redisLibeventAddRead(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_add(&e->rev,NULL); +} + +static void redisLibeventDelRead(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_del(&e->rev); +} + +static void redisLibeventAddWrite(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_add(&e->wev,NULL); +} + +static void redisLibeventDelWrite(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_del(&e->wev); +} + +static void redisLibeventCleanup(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + event_del(&e->rev); + event_del(&e->wev); + free(e); +} + +static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { + redisContext *c = &(ac->c); + redisLibeventEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibeventEvents*)malloc(sizeof(*e)); + e->context = ac; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibeventAddRead; + ac->ev.delRead = redisLibeventDelRead; + ac->ev.addWrite = redisLibeventAddWrite; + ac->ev.delWrite = redisLibeventDelWrite; + ac->ev.cleanup = redisLibeventCleanup; + ac->ev.data = e; + + /* Initialize and install read/write events */ + event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e); + event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e); + event_base_set(base,&e->rev); + event_base_set(base,&e->wev); + return REDIS_OK; +} + +#if 1 //shenzheng 2015-9-21 redis cluster + +static int redisLibeventAttach_link(redisAsyncContext *ac, void *base) +{ + redisLibeventAttach(ac, (struct event_base *)base); +} + +static int redisClusterLibeventAttach(redisClusterAsyncContext *acc, struct event_base *base) { + + if(acc == NULL || base == NULL) + { + return REDIS_ERR; + } + + acc->adapter = base; + acc->attach_fn = redisLibeventAttach_link; + + return REDIS_OK; +} + +#endif //shenzheng 2015-9-21 redis cluster + +#endif diff --git a/ext/hiredis-vip-0.3.0/adapters/libuv.h b/ext/hiredis-vip-0.3.0/adapters/libuv.h new file mode 100644 index 00000000..3c9a49f5 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adapters/libuv.h @@ -0,0 +1,122 @@ +#ifndef __HIREDIS_LIBUV_H__ +#define __HIREDIS_LIBUV_H__ +#include +#include +#include "../hiredis.h" +#include "../async.h" +#include + +typedef struct redisLibuvEvents { + redisAsyncContext* context; + uv_poll_t handle; + int events; +} redisLibuvEvents; + + +static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + + if (status != 0) { + return; + } + + if (events & UV_READABLE) { + redisAsyncHandleRead(p->context); + } + if (events & UV_WRITABLE) { + redisAsyncHandleWrite(p->context); + } +} + + +static void redisLibuvAddRead(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events |= UV_READABLE; + + uv_poll_start(&p->handle, p->events, redisLibuvPoll); +} + + +static void redisLibuvDelRead(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events &= ~UV_READABLE; + + if (p->events) { + uv_poll_start(&p->handle, p->events, redisLibuvPoll); + } else { + uv_poll_stop(&p->handle); + } +} + + +static void redisLibuvAddWrite(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events |= UV_WRITABLE; + + uv_poll_start(&p->handle, p->events, redisLibuvPoll); +} + + +static void redisLibuvDelWrite(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events &= ~UV_WRITABLE; + + if (p->events) { + uv_poll_start(&p->handle, p->events, redisLibuvPoll); + } else { + uv_poll_stop(&p->handle); + } +} + + +static void on_close(uv_handle_t* handle) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + + free(p); +} + + +static void redisLibuvCleanup(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + uv_close((uv_handle_t*)&p->handle, on_close); +} + + +static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { + redisContext *c = &(ac->c); + + if (ac->ev.data != NULL) { + return REDIS_ERR; + } + + ac->ev.addRead = redisLibuvAddRead; + ac->ev.delRead = redisLibuvDelRead; + ac->ev.addWrite = redisLibuvAddWrite; + ac->ev.delWrite = redisLibuvDelWrite; + ac->ev.cleanup = redisLibuvCleanup; + + redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p)); + + if (!p) { + return REDIS_ERR; + } + + memset(p, 0, sizeof(*p)); + + if (uv_poll_init(loop, &p->handle, c->fd) != 0) { + return REDIS_ERR; + } + + ac->ev.data = p; + p->handle.data = p; + p->context = ac; + + return REDIS_OK; +} + +#endif diff --git a/ext/hiredis-vip-0.3.0/adlist.c b/ext/hiredis-vip-0.3.0/adlist.c new file mode 100644 index 00000000..b490a6bd --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adlist.c @@ -0,0 +1,341 @@ +/* adlist.c - A generic doubly linked list implementation + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include "adlist.h" +#include "hiutil.h" + +/* Create a new list. The created list can be freed with + * AlFreeList(), but private value of every node need to be freed + * by the user before to call AlFreeList(). + * + * On error, NULL is returned. Otherwise the pointer to the new list. */ +hilist *listCreate(void) +{ + struct hilist *list; + + if ((list = hi_alloc(sizeof(*list))) == NULL) + return NULL; + list->head = list->tail = NULL; + list->len = 0; + list->dup = NULL; + list->free = NULL; + list->match = NULL; + return list; +} + +/* Free the whole list. + * + * This function can't fail. */ +void listRelease(hilist *list) +{ + unsigned long len; + listNode *current, *next; + + current = list->head; + len = list->len; + while(len--) { + next = current->next; + if (list->free) list->free(current->value); + hi_free(current); + current = next; + } + hi_free(list); +} + +/* Add a new node to the list, to head, containing the specified 'value' + * pointer as value. + * + * On error, NULL is returned and no operation is performed (i.e. the + * list remains unaltered). + * On success the 'list' pointer you pass to the function is returned. */ +hilist *listAddNodeHead(hilist *list, void *value) +{ + listNode *node; + + if ((node = hi_alloc(sizeof(*node))) == NULL) + return NULL; + node->value = value; + if (list->len == 0) { + list->head = list->tail = node; + node->prev = node->next = NULL; + } else { + node->prev = NULL; + node->next = list->head; + list->head->prev = node; + list->head = node; + } + list->len++; + return list; +} + +/* Add a new node to the list, to tail, containing the specified 'value' + * pointer as value. + * + * On error, NULL is returned and no operation is performed (i.e. the + * list remains unaltered). + * On success the 'list' pointer you pass to the function is returned. */ +hilist *listAddNodeTail(hilist *list, void *value) +{ + listNode *node; + + if ((node = hi_alloc(sizeof(*node))) == NULL) + return NULL; + node->value = value; + if (list->len == 0) { + list->head = list->tail = node; + node->prev = node->next = NULL; + } else { + node->prev = list->tail; + node->next = NULL; + list->tail->next = node; + list->tail = node; + } + list->len++; + return list; +} + +hilist *listInsertNode(hilist *list, listNode *old_node, void *value, int after) { + listNode *node; + + if ((node = hi_alloc(sizeof(*node))) == NULL) + return NULL; + node->value = value; + if (after) { + node->prev = old_node; + node->next = old_node->next; + if (list->tail == old_node) { + list->tail = node; + } + } else { + node->next = old_node; + node->prev = old_node->prev; + if (list->head == old_node) { + list->head = node; + } + } + if (node->prev != NULL) { + node->prev->next = node; + } + if (node->next != NULL) { + node->next->prev = node; + } + list->len++; + return list; +} + +/* Remove the specified node from the specified list. + * It's up to the caller to free the private value of the node. + * + * This function can't fail. */ +void listDelNode(hilist *list, listNode *node) +{ + if (node->prev) + node->prev->next = node->next; + else + list->head = node->next; + if (node->next) + node->next->prev = node->prev; + else + list->tail = node->prev; + if (list->free) list->free(node->value); + hi_free(node); + list->len--; +} + +/* Returns a list iterator 'iter'. After the initialization every + * call to listNext() will return the next element of the list. + * + * This function can't fail. */ +listIter *listGetIterator(hilist *list, int direction) +{ + listIter *iter; + + if ((iter = hi_alloc(sizeof(*iter))) == NULL) return NULL; + if (direction == AL_START_HEAD) + iter->next = list->head; + else + iter->next = list->tail; + iter->direction = direction; + return iter; +} + +/* Release the iterator memory */ +void listReleaseIterator(listIter *iter) { + hi_free(iter); +} + +/* Create an iterator in the list private iterator structure */ +void listRewind(hilist *list, listIter *li) { + li->next = list->head; + li->direction = AL_START_HEAD; +} + +void listRewindTail(hilist *list, listIter *li) { + li->next = list->tail; + li->direction = AL_START_TAIL; +} + +/* Return the next element of an iterator. + * It's valid to remove the currently returned element using + * listDelNode(), but not to remove other elements. + * + * The function returns a pointer to the next element of the list, + * or NULL if there are no more elements, so the classical usage patter + * is: + * + * iter = listGetIterator(list,); + * while ((node = listNext(iter)) != NULL) { + * doSomethingWith(listNodeValue(node)); + * } + * + * */ +listNode *listNext(listIter *iter) +{ + listNode *current = iter->next; + + if (current != NULL) { + if (iter->direction == AL_START_HEAD) + iter->next = current->next; + else + iter->next = current->prev; + } + return current; +} + +/* Duplicate the whole list. On out of memory NULL is returned. + * On success a copy of the original list is returned. + * + * The 'Dup' method set with listSetDupMethod() function is used + * to copy the node value. Otherwise the same pointer value of + * the original node is used as value of the copied node. + * + * The original list both on success or error is never modified. */ +hilist *listDup(hilist *orig) +{ + hilist *copy; + listIter *iter; + listNode *node; + + if ((copy = listCreate()) == NULL) + return NULL; + copy->dup = orig->dup; + copy->free = orig->free; + copy->match = orig->match; + iter = listGetIterator(orig, AL_START_HEAD); + while((node = listNext(iter)) != NULL) { + void *value; + + if (copy->dup) { + value = copy->dup(node->value); + if (value == NULL) { + listRelease(copy); + listReleaseIterator(iter); + return NULL; + } + } else + value = node->value; + if (listAddNodeTail(copy, value) == NULL) { + listRelease(copy); + listReleaseIterator(iter); + return NULL; + } + } + listReleaseIterator(iter); + return copy; +} + +/* Search the list for a node matching a given key. + * The match is performed using the 'match' method + * set with listSetMatchMethod(). If no 'match' method + * is set, the 'value' pointer of every node is directly + * compared with the 'key' pointer. + * + * On success the first matching node pointer is returned + * (search starts from head). If no matching node exists + * NULL is returned. */ +listNode *listSearchKey(hilist *list, void *key) +{ + listIter *iter; + listNode *node; + + iter = listGetIterator(list, AL_START_HEAD); + while((node = listNext(iter)) != NULL) { + if (list->match) { + if (list->match(node->value, key)) { + listReleaseIterator(iter); + return node; + } + } else { + if (key == node->value) { + listReleaseIterator(iter); + return node; + } + } + } + listReleaseIterator(iter); + return NULL; +} + +/* Return the element at the specified zero-based index + * where 0 is the head, 1 is the element next to head + * and so on. Negative integers are used in order to count + * from the tail, -1 is the last element, -2 the penultimate + * and so on. If the index is out of range NULL is returned. */ +listNode *listIndex(hilist *list, long index) { + listNode *n; + + if (index < 0) { + index = (-index)-1; + n = list->tail; + while(index-- && n) n = n->prev; + } else { + n = list->head; + while(index-- && n) n = n->next; + } + return n; +} + +/* Rotate the list removing the tail node and inserting it to the head. */ +void listRotate(hilist *list) { + listNode *tail = list->tail; + + if (listLength(list) <= 1) return; + + /* Detach current tail */ + list->tail = tail->prev; + list->tail->next = NULL; + /* Move it as head */ + list->head->prev = tail; + tail->prev = NULL; + tail->next = list->head; + list->head = tail; +} diff --git a/ext/hiredis-vip-0.3.0/adlist.h b/ext/hiredis-vip-0.3.0/adlist.h new file mode 100644 index 00000000..5b9a53ea --- /dev/null +++ b/ext/hiredis-vip-0.3.0/adlist.h @@ -0,0 +1,93 @@ +/* adlist.h - A generic doubly linked list implementation + * + * Copyright (c) 2006-2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ADLIST_H__ +#define __ADLIST_H__ + +/* Node, List, and Iterator are the only data structures used currently. */ + +typedef struct listNode { + struct listNode *prev; + struct listNode *next; + void *value; +} listNode; + +typedef struct listIter { + listNode *next; + int direction; +} listIter; + +typedef struct hilist { + listNode *head; + listNode *tail; + void *(*dup)(void *ptr); + void (*free)(void *ptr); + int (*match)(void *ptr, void *key); + unsigned long len; +} hilist; + +/* Functions implemented as macros */ +#define listLength(l) ((l)->len) +#define listFirst(l) ((l)->head) +#define listLast(l) ((l)->tail) +#define listPrevNode(n) ((n)->prev) +#define listNextNode(n) ((n)->next) +#define listNodeValue(n) ((n)->value) + +#define listSetDupMethod(l,m) ((l)->dup = (m)) +#define listSetFreeMethod(l,m) ((l)->free = (m)) +#define listSetMatchMethod(l,m) ((l)->match = (m)) + +#define listGetDupMethod(l) ((l)->dup) +#define listGetFree(l) ((l)->free) +#define listGetMatchMethod(l) ((l)->match) + +/* Prototypes */ +hilist *listCreate(void); +void listRelease(hilist *list); +hilist *listAddNodeHead(hilist *list, void *value); +hilist *listAddNodeTail(hilist *list, void *value); +hilist *listInsertNode(hilist *list, listNode *old_node, void *value, int after); +void listDelNode(hilist *list, listNode *node); +listIter *listGetIterator(hilist *list, int direction); +listNode *listNext(listIter *iter); +void listReleaseIterator(listIter *iter); +hilist *listDup(hilist *orig); +listNode *listSearchKey(hilist *list, void *key); +listNode *listIndex(hilist *list, long index); +void listRewind(hilist *list, listIter *li); +void listRewindTail(hilist *list, listIter *li); +void listRotate(hilist *list); + +/* Directions for iterators */ +#define AL_START_HEAD 0 +#define AL_START_TAIL 1 + +#endif /* __ADLIST_H__ */ diff --git a/ext/hiredis-vip-0.3.0/async.c b/ext/hiredis-vip-0.3.0/async.c new file mode 100644 index 00000000..75a3575d --- /dev/null +++ b/ext/hiredis-vip-0.3.0/async.c @@ -0,0 +1,691 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include "async.h" +#include "net.h" +#include "dict.c" +#include "sds.h" + +#define _EL_ADD_READ(ctx) do { \ + if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \ + } while(0) +#define _EL_DEL_READ(ctx) do { \ + if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \ + } while(0) +#define _EL_ADD_WRITE(ctx) do { \ + if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \ + } while(0) +#define _EL_DEL_WRITE(ctx) do { \ + if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \ + } while(0) +#define _EL_CLEANUP(ctx) do { \ + if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \ + } while(0); + +/* Forward declaration of function in hiredis.c */ +int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); + +/* Functions managing dictionary of callbacks for pub/sub. */ +static unsigned int callbackHash(const void *key) { + return dictGenHashFunction((const unsigned char *)key, + sdslen((const sds)key)); +} + +static void *callbackValDup(void *privdata, const void *src) { + ((void) privdata); + redisCallback *dup = malloc(sizeof(*dup)); + memcpy(dup,src,sizeof(*dup)); + return dup; +} + +static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) { + int l1, l2; + ((void) privdata); + + l1 = sdslen((const sds)key1); + l2 = sdslen((const sds)key2); + if (l1 != l2) return 0; + return memcmp(key1,key2,l1) == 0; +} + +static void callbackKeyDestructor(void *privdata, void *key) { + ((void) privdata); + sdsfree((sds)key); +} + +static void callbackValDestructor(void *privdata, void *val) { + ((void) privdata); + free(val); +} + +static dictType callbackDict = { + callbackHash, + NULL, + callbackValDup, + callbackKeyCompare, + callbackKeyDestructor, + callbackValDestructor +}; + +static redisAsyncContext *redisAsyncInitialize(redisContext *c) { + redisAsyncContext *ac; + + ac = realloc(c,sizeof(redisAsyncContext)); + if (ac == NULL) + return NULL; + + c = &(ac->c); + + /* The regular connect functions will always set the flag REDIS_CONNECTED. + * For the async API, we want to wait until the first write event is + * received up before setting this flag, so reset it here. */ + c->flags &= ~REDIS_CONNECTED; + + ac->err = 0; + ac->errstr = NULL; + ac->data = NULL; + ac->dataHandler = NULL; + + ac->ev.data = NULL; + ac->ev.addRead = NULL; + ac->ev.delRead = NULL; + ac->ev.addWrite = NULL; + ac->ev.delWrite = NULL; + ac->ev.cleanup = NULL; + + ac->onConnect = NULL; + ac->onDisconnect = NULL; + + ac->replies.head = NULL; + ac->replies.tail = NULL; + ac->sub.invalid.head = NULL; + ac->sub.invalid.tail = NULL; + ac->sub.channels = dictCreate(&callbackDict,NULL); + ac->sub.patterns = dictCreate(&callbackDict,NULL); + return ac; +} + +/* We want the error field to be accessible directly instead of requiring + * an indirection to the redisContext struct. */ +static void __redisAsyncCopyError(redisAsyncContext *ac) { + if (!ac) + return; + + redisContext *c = &(ac->c); + ac->err = c->err; + ac->errstr = c->errstr; +} + +redisAsyncContext *redisAsyncConnect(const char *ip, int port) { + redisContext *c; + redisAsyncContext *ac; + + c = redisConnectNonBlock(ip,port); + if (c == NULL) + return NULL; + + ac = redisAsyncInitialize(c); + if (ac == NULL) { + redisFree(c); + return NULL; + } + + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisConnectBindNonBlock(ip,port,source_addr); + redisAsyncContext *ac = redisAsyncInitialize(c); + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisConnectBindNonBlockWithReuse(ip,port,source_addr); + redisAsyncContext *ac = redisAsyncInitialize(c); + __redisAsyncCopyError(ac); + return ac; +} + +redisAsyncContext *redisAsyncConnectUnix(const char *path) { + redisContext *c; + redisAsyncContext *ac; + + c = redisConnectUnixNonBlock(path); + if (c == NULL) + return NULL; + + ac = redisAsyncInitialize(c); + if (ac == NULL) { + redisFree(c); + return NULL; + } + + __redisAsyncCopyError(ac); + return ac; +} + +int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { + if (ac->onConnect == NULL) { + ac->onConnect = fn; + + /* The common way to detect an established connection is to wait for + * the first write event to be fired. This assumes the related event + * library functions are already set. */ + _EL_ADD_WRITE(ac); + return REDIS_OK; + } + return REDIS_ERR; +} + +int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) { + if (ac->onDisconnect == NULL) { + ac->onDisconnect = fn; + return REDIS_OK; + } + return REDIS_ERR; +} + +/* Helper functions to push/shift callbacks */ +static int __redisPushCallback(redisCallbackList *list, redisCallback *source) { + redisCallback *cb; + + /* Copy callback from stack to heap */ + cb = malloc(sizeof(*cb)); + if (cb == NULL) + return REDIS_ERR_OOM; + + if (source != NULL) { + memcpy(cb,source,sizeof(*cb)); + cb->next = NULL; + } + + /* Store callback in list */ + if (list->head == NULL) + list->head = cb; + if (list->tail != NULL) + list->tail->next = cb; + list->tail = cb; + return REDIS_OK; +} + +static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) { + redisCallback *cb = list->head; + if (cb != NULL) { + list->head = cb->next; + if (cb == list->tail) + list->tail = NULL; + + /* Copy callback from heap to stack */ + if (target != NULL) + memcpy(target,cb,sizeof(*cb)); + free(cb); + return REDIS_OK; + } + return REDIS_ERR; +} + +static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) { + redisContext *c = &(ac->c); + if (cb->fn != NULL) { + c->flags |= REDIS_IN_CALLBACK; + cb->fn(ac,reply,cb->privdata); + c->flags &= ~REDIS_IN_CALLBACK; + } +} + +/* Helper function to free the context. */ +static void __redisAsyncFree(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisCallback cb; + dictIterator *it; + dictEntry *de; + + /* Execute pending callbacks with NULL reply. */ + while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) + __redisRunCallback(ac,&cb,NULL); + + /* Execute callbacks for invalid commands */ + while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK) + __redisRunCallback(ac,&cb,NULL); + + /* Run subscription callbacks callbacks with NULL reply */ + it = dictGetIterator(ac->sub.channels); + while ((de = dictNext(it)) != NULL) + __redisRunCallback(ac,dictGetEntryVal(de),NULL); + dictReleaseIterator(it); + dictRelease(ac->sub.channels); + + it = dictGetIterator(ac->sub.patterns); + while ((de = dictNext(it)) != NULL) + __redisRunCallback(ac,dictGetEntryVal(de),NULL); + dictReleaseIterator(it); + dictRelease(ac->sub.patterns); + + /* Signal event lib to clean up */ + _EL_CLEANUP(ac); + + /* Execute disconnect callback. When redisAsyncFree() initiated destroying + * this context, the status will always be REDIS_OK. */ + if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) { + if (c->flags & REDIS_FREEING) { + ac->onDisconnect(ac,REDIS_OK); + } else { + ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR); + } + } + + if (ac->dataHandler) { + ac->dataHandler(ac); + } + + /* Cleanup self */ + redisFree(c); +} + +/* Free the async context. When this function is called from a callback, + * control needs to be returned to redisProcessCallbacks() before actual + * free'ing. To do so, a flag is set on the context which is picked up by + * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */ +void redisAsyncFree(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + c->flags |= REDIS_FREEING; + if (!(c->flags & REDIS_IN_CALLBACK)) + __redisAsyncFree(ac); +} + +/* Helper function to make the disconnect happen and clean up. */ +static void __redisAsyncDisconnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + /* Make sure error is accessible if there is any */ + __redisAsyncCopyError(ac); + + if (ac->err == 0) { + /* For clean disconnects, there should be no pending callbacks. */ + assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR); + } else { + /* Disconnection is caused by an error, make sure that pending + * callbacks cannot call new commands. */ + c->flags |= REDIS_DISCONNECTING; + } + + /* For non-clean disconnects, __redisAsyncFree() will execute pending + * callbacks with a NULL-reply. */ + __redisAsyncFree(ac); +} + +/* Tries to do a clean disconnect from Redis, meaning it stops new commands + * from being issued, but tries to flush the output buffer and execute + * callbacks for all remaining replies. When this function is called from a + * callback, there might be more replies and we can safely defer disconnecting + * to redisProcessCallbacks(). Otherwise, we can only disconnect immediately + * when there are no pending callbacks. */ +void redisAsyncDisconnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + c->flags |= REDIS_DISCONNECTING; + if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL) + __redisAsyncDisconnect(ac); +} + +static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) { + redisContext *c = &(ac->c); + dict *callbacks; + dictEntry *de; + int pvariant; + char *stype; + sds sname; + + /* Custom reply functions are not supported for pub/sub. This will fail + * very hard when they are used... */ + if (reply->type == REDIS_REPLY_ARRAY) { + assert(reply->elements >= 2); + assert(reply->element[0]->type == REDIS_REPLY_STRING); + stype = reply->element[0]->str; + pvariant = (tolower(stype[0]) == 'p') ? 1 : 0; + + if (pvariant) + callbacks = ac->sub.patterns; + else + callbacks = ac->sub.channels; + + /* Locate the right callback */ + assert(reply->element[1]->type == REDIS_REPLY_STRING); + sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len); + de = dictFind(callbacks,sname); + if (de != NULL) { + memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb)); + + /* If this is an unsubscribe message, remove it. */ + if (strcasecmp(stype+pvariant,"unsubscribe") == 0) { + dictDelete(callbacks,sname); + + /* If this was the last unsubscribe message, revert to + * non-subscribe mode. */ + assert(reply->element[2]->type == REDIS_REPLY_INTEGER); + if (reply->element[2]->integer == 0) + c->flags &= ~REDIS_SUBSCRIBED; + } + } + sdsfree(sname); + } else { + /* Shift callback for invalid commands. */ + __redisShiftCallback(&ac->sub.invalid,dstcb); + } + return REDIS_OK; +} + +void redisProcessCallbacks(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisCallback cb = {NULL, NULL, NULL}; + void *reply = NULL; + int status; + + while((status = redisGetReply(c,&reply)) == REDIS_OK) { + if (reply == NULL) { + /* When the connection is being disconnected and there are + * no more replies, this is the cue to really disconnect. */ + if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) { + __redisAsyncDisconnect(ac); + return; + } + + /* If monitor mode, repush callback */ + if(c->flags & REDIS_MONITORING) { + __redisPushCallback(&ac->replies,&cb); + } + + /* When the connection is not being disconnected, simply stop + * trying to get replies and wait for the next loop tick. */ + break; + } + + /* Even if the context is subscribed, pending regular callbacks will + * get a reply before pub/sub messages arrive. */ + if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { + /* + * A spontaneous reply in a not-subscribed context can be the error + * reply that is sent when a new connection exceeds the maximum + * number of allowed connections on the server side. + * + * This is seen as an error instead of a regular reply because the + * server closes the connection after sending it. + * + * To prevent the error from being overwritten by an EOF error the + * connection is closed here. See issue #43. + * + * Another possibility is that the server is loading its dataset. + * In this case we also want to close the connection, and have the + * user wait until the server is ready to take our request. + */ + if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) { + c->err = REDIS_ERR_OTHER; + snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str); + c->reader->fn->freeObject(reply); + __redisAsyncDisconnect(ac); + return; + } + /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */ + assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING)); + if(c->flags & REDIS_SUBSCRIBED) + __redisGetSubscribeCallback(ac,reply,&cb); + } + + if (cb.fn != NULL) { + __redisRunCallback(ac,&cb,reply); + c->reader->fn->freeObject(reply); + + /* Proceed with free'ing when redisAsyncFree() was called. */ + if (c->flags & REDIS_FREEING) { + __redisAsyncFree(ac); + return; + } + } else { + /* No callback for this reply. This can either be a NULL callback, + * or there were no callbacks to begin with. Either way, don't + * abort with an error, but simply ignore it because the client + * doesn't know what the server will spit out over the wire. */ + c->reader->fn->freeObject(reply); + } + } + + /* Disconnect when there was an error reading the reply */ + if (status != REDIS_OK) + __redisAsyncDisconnect(ac); +} + +/* Internal helper function to detect socket status the first time a read or + * write event fires. When connecting was not succesful, the connect callback + * is called with a REDIS_ERR status and the context is free'd. */ +static int __redisAsyncHandleConnect(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + if (redisCheckSocketError(c) == REDIS_ERR) { + /* Try again later when connect(2) is still in progress. */ + if (errno == EINPROGRESS) + return REDIS_OK; + + if (ac->onConnect) ac->onConnect(ac,REDIS_ERR); + __redisAsyncDisconnect(ac); + return REDIS_ERR; + } + + /* Mark context as connected. */ + c->flags |= REDIS_CONNECTED; + if (ac->onConnect) ac->onConnect(ac,REDIS_OK); + return REDIS_OK; +} + +/* This function should be called when the socket is readable. + * It processes all replies that can be read and executes their callbacks. + */ +void redisAsyncHandleRead(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + + if (!(c->flags & REDIS_CONNECTED)) { + /* Abort connect was not successful. */ + if (__redisAsyncHandleConnect(ac) != REDIS_OK) + return; + /* Try again later when the context is still not connected. */ + if (!(c->flags & REDIS_CONNECTED)) + return; + } + + if (redisBufferRead(c) == REDIS_ERR) { + __redisAsyncDisconnect(ac); + } else { + /* Always re-schedule reads */ + _EL_ADD_READ(ac); + redisProcessCallbacks(ac); + } +} + +void redisAsyncHandleWrite(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + int done = 0; + + if (!(c->flags & REDIS_CONNECTED)) { + /* Abort connect was not successful. */ + if (__redisAsyncHandleConnect(ac) != REDIS_OK) + return; + /* Try again later when the context is still not connected. */ + if (!(c->flags & REDIS_CONNECTED)) + return; + } + + if (redisBufferWrite(c,&done) == REDIS_ERR) { + __redisAsyncDisconnect(ac); + } else { + /* Continue writing when not done, stop writing otherwise */ + if (!done) + _EL_ADD_WRITE(ac); + else + _EL_DEL_WRITE(ac); + + /* Always schedule reads after writes */ + _EL_ADD_READ(ac); + } +} + +/* Sets a pointer to the first argument and its length starting at p. Returns + * the number of bytes to skip to get to the following argument. */ +static const char *nextArgument(const char *start, const char **str, size_t *len) { + const char *p = start; + if (p[0] != '$') { + p = strchr(p,'$'); + if (p == NULL) return NULL; + } + + *len = (int)strtol(p+1,NULL,10); + p = strchr(p,'\r'); + assert(p); + *str = p+2; + return p+2+(*len)+2; +} + +/* Helper function for the redisAsyncCommand* family of functions. Writes a + * formatted command to the output buffer and registers the provided callback + * function with the context. */ +static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { + redisContext *c = &(ac->c); + redisCallback cb; + int pvariant, hasnext; + const char *cstr, *astr; + size_t clen, alen; + const char *p; + sds sname; + int ret; + + /* Don't accept new commands when the connection is about to be closed. */ + if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR; + + /* Setup callback */ + cb.fn = fn; + cb.privdata = privdata; + + /* Find out which command will be appended. */ + p = nextArgument(cmd,&cstr,&clen); + assert(p != NULL); + hasnext = (p[0] == '$'); + pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0; + cstr += pvariant; + clen -= pvariant; + + if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) { + c->flags |= REDIS_SUBSCRIBED; + + /* Add every channel/pattern to the list of subscription callbacks. */ + while ((p = nextArgument(p,&astr,&alen)) != NULL) { + sname = sdsnewlen(astr,alen); + if (pvariant) + ret = dictReplace(ac->sub.patterns,sname,&cb); + else + ret = dictReplace(ac->sub.channels,sname,&cb); + + if (ret == 0) sdsfree(sname); + } + } else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) { + /* It is only useful to call (P)UNSUBSCRIBE when the context is + * subscribed to one or more channels or patterns. */ + if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR; + + /* (P)UNSUBSCRIBE does not have its own response: every channel or + * pattern that is unsubscribed will receive a message. This means we + * should not append a callback function for this command. */ + } else if(strncasecmp(cstr,"monitor\r\n",9) == 0) { + /* Set monitor flag and push callback */ + c->flags |= REDIS_MONITORING; + __redisPushCallback(&ac->replies,&cb); + } else { + if (c->flags & REDIS_SUBSCRIBED) + /* This will likely result in an error reply, but it needs to be + * received and passed to the callback. */ + __redisPushCallback(&ac->sub.invalid,&cb); + else + __redisPushCallback(&ac->replies,&cb); + } + + __redisAppendCommand(c,cmd,len); + + /* Always schedule a write when the write buffer is non-empty */ + _EL_ADD_WRITE(ac); + + return REDIS_OK; +} + +int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) { + char *cmd; + int len; + int status; + len = redisvFormatCommand(&cmd,format,ap); + + /* We don't want to pass -1 or -2 to future functions as a length. */ + if (len < 0) + return REDIS_ERR; + + status = __redisAsyncCommand(ac,fn,privdata,cmd,len); + free(cmd); + return status; +} + +int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) { + va_list ap; + int status; + va_start(ap,format); + status = redisvAsyncCommand(ac,fn,privdata,format,ap); + va_end(ap); + return status; +} + +int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) { + sds cmd; + int len; + int status; + len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); + status = __redisAsyncCommand(ac,fn,privdata,cmd,len); + sdsfree(cmd); + return status; +} + +int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { + int status = __redisAsyncCommand(ac,fn,privdata,cmd,len); + return status; +} diff --git a/ext/hiredis-vip-0.3.0/async.h b/ext/hiredis-vip-0.3.0/async.h new file mode 100644 index 00000000..2ba7142b --- /dev/null +++ b/ext/hiredis-vip-0.3.0/async.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_ASYNC_H +#define __HIREDIS_ASYNC_H +#include "hiredis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct redisAsyncContext; /* need forward declaration of redisAsyncContext */ +struct dict; /* dictionary header is included in async.c */ + +/* Reply callback prototype and container */ +typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*); +typedef struct redisCallback { + struct redisCallback *next; /* simple singly linked list */ + redisCallbackFn *fn; + void *privdata; +} redisCallback; + +/* List of callbacks for either regular replies or pub/sub */ +typedef struct redisCallbackList { + redisCallback *head, *tail; +} redisCallbackList; + +/* Connection callback prototypes */ +typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); +typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); + +/* Context for an async connection to Redis */ +typedef struct redisAsyncContext { + /* Hold the regular context, so it can be realloc'ed. */ + redisContext c; + + /* Setup error flags so they can be used directly. */ + int err; + char *errstr; + + /* Not used by hiredis */ + void *data; + void (*dataHandler)(struct redisAsyncContext* ac); + + /* Event library data and hooks */ + struct { + void *data; + + /* Hooks that are called when the library expects to start + * reading/writing. These functions should be idempotent. */ + void (*addRead)(void *privdata); + void (*delRead)(void *privdata); + void (*addWrite)(void *privdata); + void (*delWrite)(void *privdata); + void (*cleanup)(void *privdata); + } ev; + + /* Called when either the connection is terminated due to an error or per + * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ + redisDisconnectCallback *onDisconnect; + + /* Called when the first write event was received. */ + redisConnectCallback *onConnect; + + /* Regular command callbacks */ + redisCallbackList replies; + + /* Subscription callbacks */ + struct { + redisCallbackList invalid; + struct dict *channels; + struct dict *patterns; + } sub; +} redisAsyncContext; + +/* Functions that proxy to hiredis */ +redisAsyncContext *redisAsyncConnect(const char *ip, int port); +redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr); +redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, + const char *source_addr); +redisAsyncContext *redisAsyncConnectUnix(const char *path); +int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); +int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); +void redisAsyncDisconnect(redisAsyncContext *ac); +void redisAsyncFree(redisAsyncContext *ac); + +/* Handle read/write events */ +void redisAsyncHandleRead(redisAsyncContext *ac); +void redisAsyncHandleWrite(redisAsyncContext *ac); + +/* Command functions for an async context. Write the command to the + * output buffer and register the provided callback. */ +int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap); +int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...); +int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); +int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/hiredis-vip-0.3.0/command.c b/ext/hiredis-vip-0.3.0/command.c new file mode 100644 index 00000000..e32091b4 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/command.c @@ -0,0 +1,1700 @@ +#include +#include + +#include "command.h" +#include "hiutil.h" +#include "hiarray.h" + + +static uint64_t cmd_id = 0; /* command id counter */ + + +/* + * Return true, if the redis command take no key, otherwise + * return false + */ +static int +redis_argz(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_PING: + case CMD_REQ_REDIS_QUIT: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts no arguments, otherwise + * return false + */ +static int +redis_arg0(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_EXISTS: + case CMD_REQ_REDIS_PERSIST: + case CMD_REQ_REDIS_PTTL: + case CMD_REQ_REDIS_SORT: + case CMD_REQ_REDIS_TTL: + case CMD_REQ_REDIS_TYPE: + case CMD_REQ_REDIS_DUMP: + + case CMD_REQ_REDIS_DECR: + case CMD_REQ_REDIS_GET: + case CMD_REQ_REDIS_INCR: + case CMD_REQ_REDIS_STRLEN: + + case CMD_REQ_REDIS_HGETALL: + case CMD_REQ_REDIS_HKEYS: + case CMD_REQ_REDIS_HLEN: + case CMD_REQ_REDIS_HVALS: + + case CMD_REQ_REDIS_LLEN: + case CMD_REQ_REDIS_LPOP: + case CMD_REQ_REDIS_RPOP: + + case CMD_REQ_REDIS_SCARD: + case CMD_REQ_REDIS_SMEMBERS: + case CMD_REQ_REDIS_SPOP: + + case CMD_REQ_REDIS_ZCARD: + case CMD_REQ_REDIS_PFCOUNT: + case CMD_REQ_REDIS_AUTH: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts exactly 1 argument, otherwise + * return false + */ +static int +redis_arg1(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_EXPIRE: + case CMD_REQ_REDIS_EXPIREAT: + case CMD_REQ_REDIS_PEXPIRE: + case CMD_REQ_REDIS_PEXPIREAT: + + case CMD_REQ_REDIS_APPEND: + case CMD_REQ_REDIS_DECRBY: + case CMD_REQ_REDIS_GETBIT: + case CMD_REQ_REDIS_GETSET: + case CMD_REQ_REDIS_INCRBY: + case CMD_REQ_REDIS_INCRBYFLOAT: + case CMD_REQ_REDIS_SETNX: + + case CMD_REQ_REDIS_HEXISTS: + case CMD_REQ_REDIS_HGET: + + case CMD_REQ_REDIS_LINDEX: + case CMD_REQ_REDIS_LPUSHX: + case CMD_REQ_REDIS_RPOPLPUSH: + case CMD_REQ_REDIS_RPUSHX: + + case CMD_REQ_REDIS_SISMEMBER: + + case CMD_REQ_REDIS_ZRANK: + case CMD_REQ_REDIS_ZREVRANK: + case CMD_REQ_REDIS_ZSCORE: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts exactly 2 arguments, otherwise + * return false + */ +static int +redis_arg2(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_GETRANGE: + case CMD_REQ_REDIS_PSETEX: + case CMD_REQ_REDIS_SETBIT: + case CMD_REQ_REDIS_SETEX: + case CMD_REQ_REDIS_SETRANGE: + + case CMD_REQ_REDIS_HINCRBY: + case CMD_REQ_REDIS_HINCRBYFLOAT: + case CMD_REQ_REDIS_HSET: + case CMD_REQ_REDIS_HSETNX: + + case CMD_REQ_REDIS_LRANGE: + case CMD_REQ_REDIS_LREM: + case CMD_REQ_REDIS_LSET: + case CMD_REQ_REDIS_LTRIM: + + case CMD_REQ_REDIS_SMOVE: + + case CMD_REQ_REDIS_ZCOUNT: + case CMD_REQ_REDIS_ZLEXCOUNT: + case CMD_REQ_REDIS_ZINCRBY: + case CMD_REQ_REDIS_ZREMRANGEBYLEX: + case CMD_REQ_REDIS_ZREMRANGEBYRANK: + case CMD_REQ_REDIS_ZREMRANGEBYSCORE: + + case CMD_REQ_REDIS_RESTORE: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts exactly 3 arguments, otherwise + * return false + */ +static int +redis_arg3(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_LINSERT: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts 0 or more arguments, otherwise + * return false + */ +static int +redis_argn(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_BITCOUNT: + + case CMD_REQ_REDIS_SET: + case CMD_REQ_REDIS_HDEL: + case CMD_REQ_REDIS_HMGET: + case CMD_REQ_REDIS_HMSET: + case CMD_REQ_REDIS_HSCAN: + + case CMD_REQ_REDIS_LPUSH: + case CMD_REQ_REDIS_RPUSH: + + case CMD_REQ_REDIS_SADD: + case CMD_REQ_REDIS_SDIFF: + case CMD_REQ_REDIS_SDIFFSTORE: + case CMD_REQ_REDIS_SINTER: + case CMD_REQ_REDIS_SINTERSTORE: + case CMD_REQ_REDIS_SREM: + case CMD_REQ_REDIS_SUNION: + case CMD_REQ_REDIS_SUNIONSTORE: + case CMD_REQ_REDIS_SRANDMEMBER: + case CMD_REQ_REDIS_SSCAN: + + case CMD_REQ_REDIS_PFADD: + case CMD_REQ_REDIS_PFMERGE: + + case CMD_REQ_REDIS_ZADD: + case CMD_REQ_REDIS_ZINTERSTORE: + case CMD_REQ_REDIS_ZRANGE: + case CMD_REQ_REDIS_ZRANGEBYSCORE: + case CMD_REQ_REDIS_ZREM: + case CMD_REQ_REDIS_ZREVRANGE: + case CMD_REQ_REDIS_ZRANGEBYLEX: + case CMD_REQ_REDIS_ZREVRANGEBYSCORE: + case CMD_REQ_REDIS_ZUNIONSTORE: + case CMD_REQ_REDIS_ZSCAN: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command is a vector command accepting one or + * more keys, otherwise return false + */ +static int +redis_argx(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_MGET: + case CMD_REQ_REDIS_DEL: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command is a vector command accepting one or + * more key-value pairs, otherwise return false + */ +static int +redis_argkvx(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_MSET: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command is either EVAL or EVALSHA. These commands + * have a special format with exactly 2 arguments, followed by one or more keys, + * followed by zero or more arguments (the documentation online seems to suggest + * that at least one argument is required, but that shouldn't be the case). + */ +static int +redis_argeval(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_EVAL: + case CMD_REQ_REDIS_EVALSHA: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Reference: http://redis.io/topics/protocol + * + * Redis >= 1.2 uses the unified protocol to send requests to the Redis + * server. In the unified protocol all the arguments sent to the server + * are binary safe and every request has the following general form: + * + * * CR LF + * $ CR LF + * CR LF + * ... + * $ CR LF + * CR LF + * + * Before the unified request protocol, redis protocol for requests supported + * the following commands + * 1). Inline commands: simple commands where arguments are just space + * separated strings. No binary safeness is possible. + * 2). Bulk commands: bulk commands are exactly like inline commands, but + * the last argument is handled in a special way in order to allow for + * a binary-safe last argument. + * + * only supports the Redis unified protocol for requests. + */ +void +redis_parse_cmd(struct cmd *r) +{ + int len; + char *p, *m, *token = NULL; + char *cmd_end; + char ch; + uint32_t rlen = 0; /* running length in parsing fsa */ + uint32_t rnarg = 0; /* running # arg used by parsing fsa */ + enum { + SW_START, + SW_NARG, + SW_NARG_LF, + SW_REQ_TYPE_LEN, + SW_REQ_TYPE_LEN_LF, + SW_REQ_TYPE, + SW_REQ_TYPE_LF, + SW_KEY_LEN, + SW_KEY_LEN_LF, + SW_KEY, + SW_KEY_LF, + SW_ARG1_LEN, + SW_ARG1_LEN_LF, + SW_ARG1, + SW_ARG1_LF, + SW_ARG2_LEN, + SW_ARG2_LEN_LF, + SW_ARG2, + SW_ARG2_LF, + SW_ARG3_LEN, + SW_ARG3_LEN_LF, + SW_ARG3, + SW_ARG3_LF, + SW_ARGN_LEN, + SW_ARGN_LEN_LF, + SW_ARGN, + SW_ARGN_LF, + SW_SENTINEL + } state; + + state = SW_START; + cmd_end = r->cmd + r->clen; + + ASSERT(state >= SW_START && state < SW_SENTINEL); + ASSERT(r->cmd != NULL && r->clen > 0); + + for (p = r->cmd; p < cmd_end; p++) { + ch = *p; + + switch (state) { + + case SW_START: + case SW_NARG: + if (token == NULL) { + if (ch != '*') { + goto error; + } + token = p; + /* req_start <- p */ + r->narg_start = p; + rnarg = 0; + state = SW_NARG; + } else if (isdigit(ch)) { + rnarg = rnarg * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if (rnarg == 0) { + goto error; + } + r->narg = rnarg; + r->narg_end = p; + token = NULL; + state = SW_NARG_LF; + } else { + goto error; + } + + break; + + case SW_NARG_LF: + switch (ch) { + case LF: + state = SW_REQ_TYPE_LEN; + break; + + default: + goto error; + } + + break; + + case SW_REQ_TYPE_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + token = p; + rlen = 0; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if (rlen == 0 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_REQ_TYPE_LEN_LF; + } else { + goto error; + } + + break; + + case SW_REQ_TYPE_LEN_LF: + switch (ch) { + case LF: + state = SW_REQ_TYPE; + break; + + default: + goto error; + } + + break; + + case SW_REQ_TYPE: + if (token == NULL) { + token = p; + } + + m = token + rlen; + if (m >= cmd_end) { + //m = cmd_end - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + m = token; + token = NULL; + r->type = CMD_UNKNOWN; + + switch (p - m) { + + case 3: + if (str3icmp(m, 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_GET; + break; + } + + if (str3icmp(m, 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_SET; + break; + } + + if (str3icmp(m, 't', 't', 'l')) { + r->type = CMD_REQ_REDIS_TTL; + break; + } + + if (str3icmp(m, 'd', 'e', 'l')) { + r->type = CMD_REQ_REDIS_DEL; + break; + } + + break; + + case 4: + if (str4icmp(m, 'p', 't', 't', 'l')) { + r->type = CMD_REQ_REDIS_PTTL; + break; + } + + if (str4icmp(m, 'd', 'e', 'c', 'r')) { + r->type = CMD_REQ_REDIS_DECR; + break; + } + + if (str4icmp(m, 'd', 'u', 'm', 'p')) { + r->type = CMD_REQ_REDIS_DUMP; + break; + } + + if (str4icmp(m, 'h', 'd', 'e', 'l')) { + r->type = CMD_REQ_REDIS_HDEL; + break; + } + + if (str4icmp(m, 'h', 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_HGET; + break; + } + + if (str4icmp(m, 'h', 'l', 'e', 'n')) { + r->type = CMD_REQ_REDIS_HLEN; + break; + } + + if (str4icmp(m, 'h', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_HSET; + break; + } + + if (str4icmp(m, 'i', 'n', 'c', 'r')) { + r->type = CMD_REQ_REDIS_INCR; + break; + } + + if (str4icmp(m, 'l', 'l', 'e', 'n')) { + r->type = CMD_REQ_REDIS_LLEN; + break; + } + + if (str4icmp(m, 'l', 'p', 'o', 'p')) { + r->type = CMD_REQ_REDIS_LPOP; + break; + } + + if (str4icmp(m, 'l', 'r', 'e', 'm')) { + r->type = CMD_REQ_REDIS_LREM; + break; + } + + if (str4icmp(m, 'l', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_LSET; + break; + } + + if (str4icmp(m, 'r', 'p', 'o', 'p')) { + r->type = CMD_REQ_REDIS_RPOP; + break; + } + + if (str4icmp(m, 's', 'a', 'd', 'd')) { + r->type = CMD_REQ_REDIS_SADD; + break; + } + + if (str4icmp(m, 's', 'p', 'o', 'p')) { + r->type = CMD_REQ_REDIS_SPOP; + break; + } + + if (str4icmp(m, 's', 'r', 'e', 'm')) { + r->type = CMD_REQ_REDIS_SREM; + break; + } + + if (str4icmp(m, 't', 'y', 'p', 'e')) { + r->type = CMD_REQ_REDIS_TYPE; + break; + } + + if (str4icmp(m, 'm', 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_MGET; + break; + } + if (str4icmp(m, 'm', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_MSET; + break; + } + + if (str4icmp(m, 'z', 'a', 'd', 'd')) { + r->type = CMD_REQ_REDIS_ZADD; + break; + } + + if (str4icmp(m, 'z', 'r', 'e', 'm')) { + r->type = CMD_REQ_REDIS_ZREM; + break; + } + + if (str4icmp(m, 'e', 'v', 'a', 'l')) { + r->type = CMD_REQ_REDIS_EVAL; + break; + } + + if (str4icmp(m, 's', 'o', 'r', 't')) { + r->type = CMD_REQ_REDIS_SORT; + break; + } + + if (str4icmp(m, 'p', 'i', 'n', 'g')) { + r->type = CMD_REQ_REDIS_PING; + r->noforward = 1; + break; + } + + if (str4icmp(m, 'q', 'u', 'i', 't')) { + r->type = CMD_REQ_REDIS_QUIT; + r->quit = 1; + break; + } + + if (str4icmp(m, 'a', 'u', 't', 'h')) { + r->type = CMD_REQ_REDIS_AUTH; + r->noforward = 1; + break; + } + + break; + + case 5: + if (str5icmp(m, 'h', 'k', 'e', 'y', 's')) { + r->type = CMD_REQ_REDIS_HKEYS; + break; + } + + if (str5icmp(m, 'h', 'm', 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_HMGET; + break; + } + + if (str5icmp(m, 'h', 'm', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_HMSET; + break; + } + + if (str5icmp(m, 'h', 'v', 'a', 'l', 's')) { + r->type = CMD_REQ_REDIS_HVALS; + break; + } + + if (str5icmp(m, 'h', 's', 'c', 'a', 'n')) { + r->type = CMD_REQ_REDIS_HSCAN; + break; + } + + if (str5icmp(m, 'l', 'p', 'u', 's', 'h')) { + r->type = CMD_REQ_REDIS_LPUSH; + break; + } + + if (str5icmp(m, 'l', 't', 'r', 'i', 'm')) { + r->type = CMD_REQ_REDIS_LTRIM; + break; + } + + if (str5icmp(m, 'r', 'p', 'u', 's', 'h')) { + r->type = CMD_REQ_REDIS_RPUSH; + break; + } + + if (str5icmp(m, 's', 'c', 'a', 'r', 'd')) { + r->type = CMD_REQ_REDIS_SCARD; + break; + } + + if (str5icmp(m, 's', 'd', 'i', 'f', 'f')) { + r->type = CMD_REQ_REDIS_SDIFF; + break; + } + + if (str5icmp(m, 's', 'e', 't', 'e', 'x')) { + r->type = CMD_REQ_REDIS_SETEX; + break; + } + + if (str5icmp(m, 's', 'e', 't', 'n', 'x')) { + r->type = CMD_REQ_REDIS_SETNX; + break; + } + + if (str5icmp(m, 's', 'm', 'o', 'v', 'e')) { + r->type = CMD_REQ_REDIS_SMOVE; + break; + } + + if (str5icmp(m, 's', 's', 'c', 'a', 'n')) { + r->type = CMD_REQ_REDIS_SSCAN; + break; + } + + if (str5icmp(m, 'z', 'c', 'a', 'r', 'd')) { + r->type = CMD_REQ_REDIS_ZCARD; + break; + } + + if (str5icmp(m, 'z', 'r', 'a', 'n', 'k')) { + r->type = CMD_REQ_REDIS_ZRANK; + break; + } + + if (str5icmp(m, 'z', 's', 'c', 'a', 'n')) { + r->type = CMD_REQ_REDIS_ZSCAN; + break; + } + + if (str5icmp(m, 'p', 'f', 'a', 'd', 'd')) { + r->type = CMD_REQ_REDIS_PFADD; + break; + } + + break; + + case 6: + if (str6icmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) { + r->type = CMD_REQ_REDIS_APPEND; + break; + } + + if (str6icmp(m, 'd', 'e', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_DECRBY; + break; + } + + if (str6icmp(m, 'e', 'x', 'i', 's', 't', 's')) { + r->type = CMD_REQ_REDIS_EXISTS; + break; + } + + if (str6icmp(m, 'e', 'x', 'p', 'i', 'r', 'e')) { + r->type = CMD_REQ_REDIS_EXPIRE; + break; + } + + if (str6icmp(m, 'g', 'e', 't', 'b', 'i', 't')) { + r->type = CMD_REQ_REDIS_GETBIT; + break; + } + + if (str6icmp(m, 'g', 'e', 't', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_GETSET; + break; + } + + if (str6icmp(m, 'p', 's', 'e', 't', 'e', 'x')) { + r->type = CMD_REQ_REDIS_PSETEX; + break; + } + + if (str6icmp(m, 'h', 's', 'e', 't', 'n', 'x')) { + r->type = CMD_REQ_REDIS_HSETNX; + break; + } + + if (str6icmp(m, 'i', 'n', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_INCRBY; + break; + } + + if (str6icmp(m, 'l', 'i', 'n', 'd', 'e', 'x')) { + r->type = CMD_REQ_REDIS_LINDEX; + break; + } + + if (str6icmp(m, 'l', 'p', 'u', 's', 'h', 'x')) { + r->type = CMD_REQ_REDIS_LPUSHX; + break; + } + + if (str6icmp(m, 'l', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_LRANGE; + break; + } + + if (str6icmp(m, 'r', 'p', 'u', 's', 'h', 'x')) { + r->type = CMD_REQ_REDIS_RPUSHX; + break; + } + + if (str6icmp(m, 's', 'e', 't', 'b', 'i', 't')) { + r->type = CMD_REQ_REDIS_SETBIT; + break; + } + + if (str6icmp(m, 's', 'i', 'n', 't', 'e', 'r')) { + r->type = CMD_REQ_REDIS_SINTER; + break; + } + + if (str6icmp(m, 's', 't', 'r', 'l', 'e', 'n')) { + r->type = CMD_REQ_REDIS_STRLEN; + break; + } + + if (str6icmp(m, 's', 'u', 'n', 'i', 'o', 'n')) { + r->type = CMD_REQ_REDIS_SUNION; + break; + } + + if (str6icmp(m, 'z', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_ZCOUNT; + break; + } + + if (str6icmp(m, 'z', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_ZRANGE; + break; + } + + if (str6icmp(m, 'z', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZSCORE; + break; + } + + break; + + case 7: + if (str7icmp(m, 'p', 'e', 'r', 's', 'i', 's', 't')) { + r->type = CMD_REQ_REDIS_PERSIST; + break; + } + + if (str7icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e')) { + r->type = CMD_REQ_REDIS_PEXPIRE; + break; + } + + if (str7icmp(m, 'h', 'e', 'x', 'i', 's', 't', 's')) { + r->type = CMD_REQ_REDIS_HEXISTS; + break; + } + + if (str7icmp(m, 'h', 'g', 'e', 't', 'a', 'l', 'l')) { + r->type = CMD_REQ_REDIS_HGETALL; + break; + } + + if (str7icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_HINCRBY; + break; + } + + if (str7icmp(m, 'l', 'i', 'n', 's', 'e', 'r', 't')) { + r->type = CMD_REQ_REDIS_LINSERT; + break; + } + + if (str7icmp(m, 'z', 'i', 'n', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_ZINCRBY; + break; + } + + if (str7icmp(m, 'e', 'v', 'a', 'l', 's', 'h', 'a')) { + r->type = CMD_REQ_REDIS_EVALSHA; + break; + } + + if (str7icmp(m, 'r', 'e', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_RESTORE; + break; + } + + if (str7icmp(m, 'p', 'f', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_PFCOUNT; + break; + } + + if (str7icmp(m, 'p', 'f', 'm', 'e', 'r', 'g', 'e')) { + r->type = CMD_REQ_REDIS_PFMERGE; + break; + } + + break; + + case 8: + if (str8icmp(m, 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) { + r->type = CMD_REQ_REDIS_EXPIREAT; + break; + } + + if (str8icmp(m, 'b', 'i', 't', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_BITCOUNT; + break; + } + + if (str8icmp(m, 'g', 'e', 't', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_GETRANGE; + break; + } + + if (str8icmp(m, 's', 'e', 't', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_SETRANGE; + break; + } + + if (str8icmp(m, 's', 'm', 'e', 'm', 'b', 'e', 'r', 's')) { + r->type = CMD_REQ_REDIS_SMEMBERS; + break; + } + + if (str8icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'k')) { + r->type = CMD_REQ_REDIS_ZREVRANK; + break; + } + + break; + + case 9: + if (str9icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) { + r->type = CMD_REQ_REDIS_PEXPIREAT; + break; + } + + if (str9icmp(m, 'r', 'p', 'o', 'p', 'l', 'p', 'u', 's', 'h')) { + r->type = CMD_REQ_REDIS_RPOPLPUSH; + break; + } + + if (str9icmp(m, 's', 'i', 's', 'm', 'e', 'm', 'b', 'e', 'r')) { + r->type = CMD_REQ_REDIS_SISMEMBER; + break; + } + + if (str9icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_ZREVRANGE; + break; + } + + if (str9icmp(m, 'z', 'l', 'e', 'x', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_ZLEXCOUNT; + break; + } + + break; + + case 10: + if (str10icmp(m, 's', 'd', 'i', 'f', 'f', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_SDIFFSTORE; + break; + } + + case 11: + if (str11icmp(m, 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) { + r->type = CMD_REQ_REDIS_INCRBYFLOAT; + break; + } + + if (str11icmp(m, 's', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_SINTERSTORE; + break; + } + + if (str11icmp(m, 's', 'r', 'a', 'n', 'd', 'm', 'e', 'm', 'b', 'e', 'r')) { + r->type = CMD_REQ_REDIS_SRANDMEMBER; + break; + } + + if (str11icmp(m, 's', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_SUNIONSTORE; + break; + } + + if (str11icmp(m, 'z', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZINTERSTORE; + break; + } + + if (str11icmp(m, 'z', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZUNIONSTORE; + break; + } + + if (str11icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) { + r->type = CMD_REQ_REDIS_ZRANGEBYLEX; + break; + } + + break; + + case 12: + if (str12icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) { + r->type = CMD_REQ_REDIS_HINCRBYFLOAT; + break; + } + + + break; + + case 13: + if (str13icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZRANGEBYSCORE; + break; + } + + break; + + case 14: + if (str14icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) { + r->type = CMD_REQ_REDIS_ZREMRANGEBYLEX; + break; + } + + break; + + case 15: + if (str15icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'r', 'a', 'n', 'k')) { + r->type = CMD_REQ_REDIS_ZREMRANGEBYRANK; + break; + } + + break; + + case 16: + if (str16icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZREMRANGEBYSCORE; + break; + } + + if (str16icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZREVRANGEBYSCORE; + break; + } + + break; + + default: + break; + } + + if (r->type == CMD_UNKNOWN) { + goto error; + } + + state = SW_REQ_TYPE_LF; + break; + + case SW_REQ_TYPE_LF: + switch (ch) { + case LF: + if (redis_argz(r)) { + goto done; + } else if (redis_argeval(r)) { + state = SW_ARG1_LEN; + } else { + state = SW_KEY_LEN; + } + break; + + default: + goto error; + } + + break; + + case SW_KEY_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + token = p; + rlen = 0; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + + if (rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_KEY_LEN_LF; + } else { + goto error; + } + + break; + + case SW_KEY_LEN_LF: + switch (ch) { + case LF: + state = SW_KEY; + break; + + default: + goto error; + } + + break; + + case SW_KEY: + if (token == NULL) { + token = p; + } + + m = token + rlen; + if (m >= cmd_end) { + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } else { /* got a key */ + struct keypos *kpos; + + p = m; /* move forward by rlen bytes */ + rlen = 0; + m = token; + token = NULL; + + kpos = hiarray_push(r->keys); + if (kpos == NULL) { + goto enomem; + } + kpos->start = m; + kpos->end = p; + //kpos->v_len = 0; + + state = SW_KEY_LF; + } + + break; + + case SW_KEY_LF: + switch (ch) { + case LF: + if (redis_arg0(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_arg1(r)) { + if (rnarg != 1) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_arg2(r)) { + if (rnarg != 2) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_arg3(r)) { + if (rnarg != 3) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARG1_LEN; + } else if (redis_argx(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_KEY_LEN; + } else if (redis_argkvx(r)) { + if (rnarg == 0) { + goto done; + } + if (r->narg % 2 == 0) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_argeval(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARG1_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + + /* + //for mset value length + if(redis_argkvx(r)) + { + struct keypos *kpos; + uint32_t array_len = array_n(r->keys); + if(array_len == 0) + { + goto error; + } + + kpos = array_n(r->keys, array_len-1); + if (kpos == NULL || kpos->v_len != 0) { + goto error; + } + + kpos->v_len = rlen; + } + */ + state = SW_ARG1_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARG1_LEN_LF: + switch (ch) { + case LF: + state = SW_ARG1; + break; + + default: + goto error; + } + + break; + + case SW_ARG1: + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + + state = SW_ARG1_LF; + + break; + + case SW_ARG1_LF: + switch (ch) { + case LF: + if (redis_arg1(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_arg2(r)) { + if (rnarg != 1) { + goto error; + } + state = SW_ARG2_LEN; + } else if (redis_arg3(r)) { + if (rnarg != 2) { + goto error; + } + state = SW_ARG2_LEN; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else if (redis_argeval(r)) { + if (rnarg < 2) { + goto error; + } + state = SW_ARG2_LEN; + } else if (redis_argkvx(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_KEY_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARG2_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_ARG2_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARG2_LEN_LF: + switch (ch) { + case LF: + state = SW_ARG2; + break; + + default: + goto error; + } + + break; + + case SW_ARG2: + if (token == NULL && redis_argeval(r)) { + /* + * For EVAL/EVALSHA, ARG2 represents the # key/arg pairs which must + * be tokenized and stored in contiguous memory. + */ + token = p; + } + + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + + if (redis_argeval(r)) { + uint32_t nkey; + char *chp; + + /* + * For EVAL/EVALSHA, we need to find the integer value of this + * argument. It tells us the number of keys in the script, and + * we need to error out if number of keys is 0. At this point, + * both p and m point to the end of the argument and r->token + * points to the start. + */ + if (p - token < 1) { + goto error; + } + + for (nkey = 0, chp = token; chp < p; chp++) { + if (isdigit(*chp)) { + nkey = nkey * 10 + (uint32_t)(*chp - '0'); + } else { + goto error; + } + } + if (nkey == 0) { + goto error; + } + + token = NULL; + } + + state = SW_ARG2_LF; + + break; + + case SW_ARG2_LF: + switch (ch) { + case LF: + if (redis_arg2(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_arg3(r)) { + if (rnarg != 1) { + goto error; + } + state = SW_ARG3_LEN; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else if (redis_argeval(r)) { + if (rnarg < 1) { + goto error; + } + state = SW_KEY_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARG3_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_ARG3_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARG3_LEN_LF: + switch (ch) { + case LF: + state = SW_ARG3; + break; + + default: + goto error; + } + + break; + + case SW_ARG3: + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + state = SW_ARG3_LF; + + break; + + case SW_ARG3_LF: + switch (ch) { + case LF: + if (redis_arg3(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARGN_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_ARGN_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARGN_LEN_LF: + switch (ch) { + case LF: + state = SW_ARGN; + break; + + default: + goto error; + } + + break; + + case SW_ARGN: + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + state = SW_ARGN_LF; + + break; + + case SW_ARGN_LF: + switch (ch) { + case LF: + if (redis_argn(r) || redis_argeval(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_SENTINEL: + default: + NOT_REACHED(); + break; + } + } + + ASSERT(p == cmd_end); + + return; + +done: + + ASSERT(r->type > CMD_UNKNOWN && r->type < CMD_SENTINEL); + + r->result = CMD_PARSE_OK; + + return; + +enomem: + + r->result = CMD_PARSE_ENOMEM; + + return; + +error: + + r->result = CMD_PARSE_ERROR; + errno = EINVAL; + if(r->errstr == NULL){ + r->errstr = hi_alloc(100*sizeof(*r->errstr)); + } + + len = _scnprintf(r->errstr, 100, "Parse command error. Cmd type: %d, state: %d, break position: %d.", + r->type, state, (int)(p - r->cmd)); + r->errstr[len] = '\0'; +} + +struct cmd *command_get() +{ + struct cmd *command; + command = hi_alloc(sizeof(struct cmd)); + if(command == NULL) + { + return NULL; + } + + command->id = ++cmd_id; + command->result = CMD_PARSE_OK; + command->errstr = NULL; + command->type = CMD_UNKNOWN; + command->cmd = NULL; + command->clen = 0; + command->keys = NULL; + command->narg_start = NULL; + command->narg_end = NULL; + command->narg = 0; + command->quit = 0; + command->noforward = 0; + command->slot_num = -1; + command->frag_seq = NULL; + command->reply = NULL; + command->sub_commands = NULL; + + command->keys = hiarray_create(1, sizeof(struct keypos)); + if (command->keys == NULL) + { + hi_free(command); + return NULL; + } + + return command; +} + +void command_destroy(struct cmd *command) +{ + if(command == NULL) + { + return; + } + + if(command->cmd != NULL) + { + free(command->cmd); + } + + if(command->errstr != NULL){ + hi_free(command->errstr); + } + + if(command->keys != NULL) + { + command->keys->nelem = 0; + hiarray_destroy(command->keys); + } + + if(command->frag_seq != NULL) + { + hi_free(command->frag_seq); + command->frag_seq = NULL; + } + + if(command->reply != NULL) + { + freeReplyObject(command->reply); + } + + if(command->sub_commands != NULL) + { + listRelease(command->sub_commands); + } + + hi_free(command); +} + + diff --git a/ext/hiredis-vip-0.3.0/command.h b/ext/hiredis-vip-0.3.0/command.h new file mode 100644 index 00000000..b7c388a6 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/command.h @@ -0,0 +1,179 @@ +#ifndef __COMMAND_H_ +#define __COMMAND_H_ + +#include + +#include "hiredis.h" +#include "adlist.h" + +typedef enum cmd_parse_result { + CMD_PARSE_OK, /* parsing ok */ + CMD_PARSE_ENOMEM, /* out of memory */ + CMD_PARSE_ERROR, /* parsing error */ + CMD_PARSE_REPAIR, /* more to parse -> repair parsed & unparsed data */ + CMD_PARSE_AGAIN, /* incomplete -> parse again */ +} cmd_parse_result_t; + +#define CMD_TYPE_CODEC(ACTION) \ + ACTION( UNKNOWN ) \ + ACTION( REQ_REDIS_DEL ) /* redis commands - keys */ \ + ACTION( REQ_REDIS_EXISTS ) \ + ACTION( REQ_REDIS_EXPIRE ) \ + ACTION( REQ_REDIS_EXPIREAT ) \ + ACTION( REQ_REDIS_PEXPIRE ) \ + ACTION( REQ_REDIS_PEXPIREAT ) \ + ACTION( REQ_REDIS_PERSIST ) \ + ACTION( REQ_REDIS_PTTL ) \ + ACTION( REQ_REDIS_SORT ) \ + ACTION( REQ_REDIS_TTL ) \ + ACTION( REQ_REDIS_TYPE ) \ + ACTION( REQ_REDIS_APPEND ) /* redis requests - string */ \ + ACTION( REQ_REDIS_BITCOUNT ) \ + ACTION( REQ_REDIS_DECR ) \ + ACTION( REQ_REDIS_DECRBY ) \ + ACTION( REQ_REDIS_DUMP ) \ + ACTION( REQ_REDIS_GET ) \ + ACTION( REQ_REDIS_GETBIT ) \ + ACTION( REQ_REDIS_GETRANGE ) \ + ACTION( REQ_REDIS_GETSET ) \ + ACTION( REQ_REDIS_INCR ) \ + ACTION( REQ_REDIS_INCRBY ) \ + ACTION( REQ_REDIS_INCRBYFLOAT ) \ + ACTION( REQ_REDIS_MGET ) \ + ACTION( REQ_REDIS_MSET ) \ + ACTION( REQ_REDIS_PSETEX ) \ + ACTION( REQ_REDIS_RESTORE ) \ + ACTION( REQ_REDIS_SET ) \ + ACTION( REQ_REDIS_SETBIT ) \ + ACTION( REQ_REDIS_SETEX ) \ + ACTION( REQ_REDIS_SETNX ) \ + ACTION( REQ_REDIS_SETRANGE ) \ + ACTION( REQ_REDIS_STRLEN ) \ + ACTION( REQ_REDIS_HDEL ) /* redis requests - hashes */ \ + ACTION( REQ_REDIS_HEXISTS ) \ + ACTION( REQ_REDIS_HGET ) \ + ACTION( REQ_REDIS_HGETALL ) \ + ACTION( REQ_REDIS_HINCRBY ) \ + ACTION( REQ_REDIS_HINCRBYFLOAT ) \ + ACTION( REQ_REDIS_HKEYS ) \ + ACTION( REQ_REDIS_HLEN ) \ + ACTION( REQ_REDIS_HMGET ) \ + ACTION( REQ_REDIS_HMSET ) \ + ACTION( REQ_REDIS_HSET ) \ + ACTION( REQ_REDIS_HSETNX ) \ + ACTION( REQ_REDIS_HSCAN) \ + ACTION( REQ_REDIS_HVALS ) \ + ACTION( REQ_REDIS_LINDEX ) /* redis requests - lists */ \ + ACTION( REQ_REDIS_LINSERT ) \ + ACTION( REQ_REDIS_LLEN ) \ + ACTION( REQ_REDIS_LPOP ) \ + ACTION( REQ_REDIS_LPUSH ) \ + ACTION( REQ_REDIS_LPUSHX ) \ + ACTION( REQ_REDIS_LRANGE ) \ + ACTION( REQ_REDIS_LREM ) \ + ACTION( REQ_REDIS_LSET ) \ + ACTION( REQ_REDIS_LTRIM ) \ + ACTION( REQ_REDIS_PFADD ) /* redis requests - hyperloglog */ \ + ACTION( REQ_REDIS_PFCOUNT ) \ + ACTION( REQ_REDIS_PFMERGE ) \ + ACTION( REQ_REDIS_RPOP ) \ + ACTION( REQ_REDIS_RPOPLPUSH ) \ + ACTION( REQ_REDIS_RPUSH ) \ + ACTION( REQ_REDIS_RPUSHX ) \ + ACTION( REQ_REDIS_SADD ) /* redis requests - sets */ \ + ACTION( REQ_REDIS_SCARD ) \ + ACTION( REQ_REDIS_SDIFF ) \ + ACTION( REQ_REDIS_SDIFFSTORE ) \ + ACTION( REQ_REDIS_SINTER ) \ + ACTION( REQ_REDIS_SINTERSTORE ) \ + ACTION( REQ_REDIS_SISMEMBER ) \ + ACTION( REQ_REDIS_SMEMBERS ) \ + ACTION( REQ_REDIS_SMOVE ) \ + ACTION( REQ_REDIS_SPOP ) \ + ACTION( REQ_REDIS_SRANDMEMBER ) \ + ACTION( REQ_REDIS_SREM ) \ + ACTION( REQ_REDIS_SUNION ) \ + ACTION( REQ_REDIS_SUNIONSTORE ) \ + ACTION( REQ_REDIS_SSCAN) \ + ACTION( REQ_REDIS_ZADD ) /* redis requests - sorted sets */ \ + ACTION( REQ_REDIS_ZCARD ) \ + ACTION( REQ_REDIS_ZCOUNT ) \ + ACTION( REQ_REDIS_ZINCRBY ) \ + ACTION( REQ_REDIS_ZINTERSTORE ) \ + ACTION( REQ_REDIS_ZLEXCOUNT ) \ + ACTION( REQ_REDIS_ZRANGE ) \ + ACTION( REQ_REDIS_ZRANGEBYLEX ) \ + ACTION( REQ_REDIS_ZRANGEBYSCORE ) \ + ACTION( REQ_REDIS_ZRANK ) \ + ACTION( REQ_REDIS_ZREM ) \ + ACTION( REQ_REDIS_ZREMRANGEBYRANK ) \ + ACTION( REQ_REDIS_ZREMRANGEBYLEX ) \ + ACTION( REQ_REDIS_ZREMRANGEBYSCORE ) \ + ACTION( REQ_REDIS_ZREVRANGE ) \ + ACTION( REQ_REDIS_ZREVRANGEBYSCORE ) \ + ACTION( REQ_REDIS_ZREVRANK ) \ + ACTION( REQ_REDIS_ZSCORE ) \ + ACTION( REQ_REDIS_ZUNIONSTORE ) \ + ACTION( REQ_REDIS_ZSCAN) \ + ACTION( REQ_REDIS_EVAL ) /* redis requests - eval */ \ + ACTION( REQ_REDIS_EVALSHA ) \ + ACTION( REQ_REDIS_PING ) /* redis requests - ping/quit */ \ + ACTION( REQ_REDIS_QUIT) \ + ACTION( REQ_REDIS_AUTH) \ + ACTION( RSP_REDIS_STATUS ) /* redis response */ \ + ACTION( RSP_REDIS_ERROR ) \ + ACTION( RSP_REDIS_INTEGER ) \ + ACTION( RSP_REDIS_BULK ) \ + ACTION( RSP_REDIS_MULTIBULK ) \ + ACTION( SENTINEL ) \ + + +#define DEFINE_ACTION(_name) CMD_##_name, +typedef enum cmd_type { + CMD_TYPE_CODEC(DEFINE_ACTION) +} cmd_type_t; +#undef DEFINE_ACTION + + +struct keypos { + char *start; /* key start pos */ + char *end; /* key end pos */ + uint32_t remain_len; /* remain length after keypos->end for more key-value pairs in command, like mset */ +}; + +struct cmd { + + uint64_t id; /* command id */ + + cmd_parse_result_t result; /* command parsing result */ + char *errstr; /* error info when the command parse failed */ + + cmd_type_t type; /* command type */ + + char *cmd; + uint32_t clen; /* command length */ + + struct hiarray *keys; /* array of keypos, for req */ + + char *narg_start; /* narg start (redis) */ + char *narg_end; /* narg end (redis) */ + uint32_t narg; /* # arguments (redis) */ + + unsigned quit:1; /* quit request? */ + unsigned noforward:1; /* not need forward (example: ping) */ + + int slot_num; /* this command should send to witch slot? + * -1:the keys in this command cross different slots*/ + struct cmd **frag_seq; /* sequence of fragment command, map from keys to fragments*/ + + redisReply *reply; + + hilist *sub_commands; /* just for pipeline and multi-key commands */ +}; + +void redis_parse_cmd(struct cmd *r); + +struct cmd *command_get(void); +void command_destroy(struct cmd *command); + +#endif diff --git a/ext/hiredis-vip-0.3.0/crc16.c b/ext/hiredis-vip-0.3.0/crc16.c new file mode 100644 index 00000000..0f304f6e --- /dev/null +++ b/ext/hiredis-vip-0.3.0/crc16.c @@ -0,0 +1,87 @@ +/* + * Copyright 2001-2010 Georges Menie (www.menie.org) + * Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* CRC16 implementation according to CCITT standards. + * + * Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the + * following parameters: + * + * Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN" + * Width : 16 bit + * Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1) + * Initialization : 0000 + * Reflect Input byte : False + * Reflect Output CRC : False + * Xor constant to output CRC : 0000 + * Output for "123456789" : 31C3 + */ +#include "hiutil.h" + +static const uint16_t crc16tab[256]= { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +uint16_t crc16(const char *buf, int len) { + int counter; + uint16_t crc = 0; + for (counter = 0; counter < len; counter++) + crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF]; + return crc; +} diff --git a/ext/hiredis-vip-0.3.0/dict.c b/ext/hiredis-vip-0.3.0/dict.c new file mode 100644 index 00000000..79b1041c --- /dev/null +++ b/ext/hiredis-vip-0.3.0/dict.c @@ -0,0 +1,338 @@ +/* Hash table implementation. + * + * This file implements in memory hash tables with insert/del/replace/find/ + * get-random-element operations. Hash tables will auto resize if needed + * tables of power of two in size are used, collisions are handled by + * chaining. See the source code for more information... :) + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmacros.h" +#include +#include +#include +#include "dict.h" + +/* -------------------------- private prototypes ---------------------------- */ + +static int _dictExpandIfNeeded(dict *ht); +static unsigned long _dictNextPower(unsigned long size); +static int _dictKeyIndex(dict *ht, const void *key); +static int _dictInit(dict *ht, dictType *type, void *privDataPtr); + +/* -------------------------- hash functions -------------------------------- */ + +/* Generic hash function (a popular one from Bernstein). + * I tested a few and this was the best. */ +static unsigned int dictGenHashFunction(const unsigned char *buf, int len) { + unsigned int hash = 5381; + + while (len--) + hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */ + return hash; +} + +/* ----------------------------- API implementation ------------------------- */ + +/* Reset an hashtable already initialized with ht_init(). + * NOTE: This function should only called by ht_destroy(). */ +static void _dictReset(dict *ht) { + ht->table = NULL; + ht->size = 0; + ht->sizemask = 0; + ht->used = 0; +} + +/* Create a new hash table */ +static dict *dictCreate(dictType *type, void *privDataPtr) { + dict *ht = malloc(sizeof(*ht)); + _dictInit(ht,type,privDataPtr); + return ht; +} + +/* Initialize the hash table */ +static int _dictInit(dict *ht, dictType *type, void *privDataPtr) { + _dictReset(ht); + ht->type = type; + ht->privdata = privDataPtr; + return DICT_OK; +} + +/* Expand or create the hashtable */ +static int dictExpand(dict *ht, unsigned long size) { + dict n; /* the new hashtable */ + unsigned long realsize = _dictNextPower(size), i; + + /* the size is invalid if it is smaller than the number of + * elements already inside the hashtable */ + if (ht->used > size) + return DICT_ERR; + + _dictInit(&n, ht->type, ht->privdata); + n.size = realsize; + n.sizemask = realsize-1; + n.table = calloc(realsize,sizeof(dictEntry*)); + + /* Copy all the elements from the old to the new table: + * note that if the old hash table is empty ht->size is zero, + * so dictExpand just creates an hash table. */ + n.used = ht->used; + for (i = 0; i < ht->size && ht->used > 0; i++) { + dictEntry *he, *nextHe; + + if (ht->table[i] == NULL) continue; + + /* For each hash entry on this slot... */ + he = ht->table[i]; + while(he) { + unsigned int h; + + nextHe = he->next; + /* Get the new element index */ + h = dictHashKey(ht, he->key) & n.sizemask; + he->next = n.table[h]; + n.table[h] = he; + ht->used--; + /* Pass to the next element */ + he = nextHe; + } + } + assert(ht->used == 0); + free(ht->table); + + /* Remap the new hashtable in the old */ + *ht = n; + return DICT_OK; +} + +/* Add an element to the target hash table */ +static int dictAdd(dict *ht, void *key, void *val) { + int index; + dictEntry *entry; + + /* Get the index of the new element, or -1 if + * the element already exists. */ + if ((index = _dictKeyIndex(ht, key)) == -1) + return DICT_ERR; + + /* Allocates the memory and stores key */ + entry = malloc(sizeof(*entry)); + entry->next = ht->table[index]; + ht->table[index] = entry; + + /* Set the hash entry fields. */ + dictSetHashKey(ht, entry, key); + dictSetHashVal(ht, entry, val); + ht->used++; + return DICT_OK; +} + +/* Add an element, discarding the old if the key already exists. + * Return 1 if the key was added from scratch, 0 if there was already an + * element with such key and dictReplace() just performed a value update + * operation. */ +static int dictReplace(dict *ht, void *key, void *val) { + dictEntry *entry, auxentry; + + /* Try to add the element. If the key + * does not exists dictAdd will suceed. */ + if (dictAdd(ht, key, val) == DICT_OK) + return 1; + /* It already exists, get the entry */ + entry = dictFind(ht, key); + /* Free the old value and set the new one */ + /* Set the new value and free the old one. Note that it is important + * to do that in this order, as the value may just be exactly the same + * as the previous one. In this context, think to reference counting, + * you want to increment (set), and then decrement (free), and not the + * reverse. */ + auxentry = *entry; + dictSetHashVal(ht, entry, val); + dictFreeEntryVal(ht, &auxentry); + return 0; +} + +/* Search and remove an element */ +static int dictDelete(dict *ht, const void *key) { + unsigned int h; + dictEntry *de, *prevde; + + if (ht->size == 0) + return DICT_ERR; + h = dictHashKey(ht, key) & ht->sizemask; + de = ht->table[h]; + + prevde = NULL; + while(de) { + if (dictCompareHashKeys(ht,key,de->key)) { + /* Unlink the element from the list */ + if (prevde) + prevde->next = de->next; + else + ht->table[h] = de->next; + + dictFreeEntryKey(ht,de); + dictFreeEntryVal(ht,de); + free(de); + ht->used--; + return DICT_OK; + } + prevde = de; + de = de->next; + } + return DICT_ERR; /* not found */ +} + +/* Destroy an entire hash table */ +static int _dictClear(dict *ht) { + unsigned long i; + + /* Free all the elements */ + for (i = 0; i < ht->size && ht->used > 0; i++) { + dictEntry *he, *nextHe; + + if ((he = ht->table[i]) == NULL) continue; + while(he) { + nextHe = he->next; + dictFreeEntryKey(ht, he); + dictFreeEntryVal(ht, he); + free(he); + ht->used--; + he = nextHe; + } + } + /* Free the table and the allocated cache structure */ + free(ht->table); + /* Re-initialize the table */ + _dictReset(ht); + return DICT_OK; /* never fails */ +} + +/* Clear & Release the hash table */ +static void dictRelease(dict *ht) { + _dictClear(ht); + free(ht); +} + +static dictEntry *dictFind(dict *ht, const void *key) { + dictEntry *he; + unsigned int h; + + if (ht->size == 0) return NULL; + h = dictHashKey(ht, key) & ht->sizemask; + he = ht->table[h]; + while(he) { + if (dictCompareHashKeys(ht, key, he->key)) + return he; + he = he->next; + } + return NULL; +} + +static dictIterator *dictGetIterator(dict *ht) { + dictIterator *iter = malloc(sizeof(*iter)); + + iter->ht = ht; + iter->index = -1; + iter->entry = NULL; + iter->nextEntry = NULL; + return iter; +} + +static dictEntry *dictNext(dictIterator *iter) { + while (1) { + if (iter->entry == NULL) { + iter->index++; + if (iter->index >= + (signed)iter->ht->size) break; + iter->entry = iter->ht->table[iter->index]; + } else { + iter->entry = iter->nextEntry; + } + if (iter->entry) { + /* We need to save the 'next' here, the iterator user + * may delete the entry we are returning. */ + iter->nextEntry = iter->entry->next; + return iter->entry; + } + } + return NULL; +} + +static void dictReleaseIterator(dictIterator *iter) { + free(iter); +} + +/* ------------------------- private functions ------------------------------ */ + +/* Expand the hash table if needed */ +static int _dictExpandIfNeeded(dict *ht) { + /* If the hash table is empty expand it to the intial size, + * if the table is "full" dobule its size. */ + if (ht->size == 0) + return dictExpand(ht, DICT_HT_INITIAL_SIZE); + if (ht->used == ht->size) + return dictExpand(ht, ht->size*2); + return DICT_OK; +} + +/* Our hash table capability is a power of two */ +static unsigned long _dictNextPower(unsigned long size) { + unsigned long i = DICT_HT_INITIAL_SIZE; + + if (size >= LONG_MAX) return LONG_MAX; + while(1) { + if (i >= size) + return i; + i *= 2; + } +} + +/* Returns the index of a free slot that can be populated with + * an hash entry for the given 'key'. + * If the key already exists, -1 is returned. */ +static int _dictKeyIndex(dict *ht, const void *key) { + unsigned int h; + dictEntry *he; + + /* Expand the hashtable if needed */ + if (_dictExpandIfNeeded(ht) == DICT_ERR) + return -1; + /* Compute the key hash value */ + h = dictHashKey(ht, key) & ht->sizemask; + /* Search if this slot does not already contain the given key */ + he = ht->table[h]; + while(he) { + if (dictCompareHashKeys(ht, key, he->key)) + return -1; + he = he->next; + } + return h; +} + diff --git a/ext/hiredis-vip-0.3.0/dict.h b/ext/hiredis-vip-0.3.0/dict.h new file mode 100644 index 00000000..95fcd280 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/dict.h @@ -0,0 +1,126 @@ +/* Hash table implementation. + * + * This file implements in memory hash tables with insert/del/replace/find/ + * get-random-element operations. Hash tables will auto resize if needed + * tables of power of two in size are used, collisions are handled by + * chaining. See the source code for more information... :) + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DICT_H +#define __DICT_H + +#define DICT_OK 0 +#define DICT_ERR 1 + +/* Unused arguments generate annoying warnings... */ +#define DICT_NOTUSED(V) ((void) V) + +typedef struct dictEntry { + void *key; + void *val; + struct dictEntry *next; +} dictEntry; + +typedef struct dictType { + unsigned int (*hashFunction)(const void *key); + void *(*keyDup)(void *privdata, const void *key); + void *(*valDup)(void *privdata, const void *obj); + int (*keyCompare)(void *privdata, const void *key1, const void *key2); + void (*keyDestructor)(void *privdata, void *key); + void (*valDestructor)(void *privdata, void *obj); +} dictType; + +typedef struct dict { + dictEntry **table; + dictType *type; + unsigned long size; + unsigned long sizemask; + unsigned long used; + void *privdata; +} dict; + +typedef struct dictIterator { + dict *ht; + int index; + dictEntry *entry, *nextEntry; +} dictIterator; + +/* This is the initial size of every hash table */ +#define DICT_HT_INITIAL_SIZE 4 + +/* ------------------------------- Macros ------------------------------------*/ +#define dictFreeEntryVal(ht, entry) \ + if ((ht)->type->valDestructor) \ + (ht)->type->valDestructor((ht)->privdata, (entry)->val) + +#define dictSetHashVal(ht, entry, _val_) do { \ + if ((ht)->type->valDup) \ + entry->val = (ht)->type->valDup((ht)->privdata, _val_); \ + else \ + entry->val = (_val_); \ +} while(0) + +#define dictFreeEntryKey(ht, entry) \ + if ((ht)->type->keyDestructor) \ + (ht)->type->keyDestructor((ht)->privdata, (entry)->key) + +#define dictSetHashKey(ht, entry, _key_) do { \ + if ((ht)->type->keyDup) \ + entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ + else \ + entry->key = (_key_); \ +} while(0) + +#define dictCompareHashKeys(ht, key1, key2) \ + (((ht)->type->keyCompare) ? \ + (ht)->type->keyCompare((ht)->privdata, key1, key2) : \ + (key1) == (key2)) + +#define dictHashKey(ht, key) (ht)->type->hashFunction(key) + +#define dictGetEntryKey(he) ((he)->key) +#define dictGetEntryVal(he) ((he)->val) +#define dictSlots(ht) ((ht)->size) +#define dictSize(ht) ((ht)->used) + +/* API */ +static unsigned int dictGenHashFunction(const unsigned char *buf, int len); +static dict *dictCreate(dictType *type, void *privDataPtr); +static int dictExpand(dict *ht, unsigned long size); +static int dictAdd(dict *ht, void *key, void *val); +static int dictReplace(dict *ht, void *key, void *val); +static int dictDelete(dict *ht, const void *key); +static void dictRelease(dict *ht); +static dictEntry * dictFind(dict *ht, const void *key); +static dictIterator *dictGetIterator(dict *ht); +static dictEntry *dictNext(dictIterator *iter); +static void dictReleaseIterator(dictIterator *iter); + +#endif /* __DICT_H */ diff --git a/ext/hiredis-vip-0.3.0/examples/example-ae.c b/ext/hiredis-vip-0.3.0/examples/example-ae.c new file mode 100644 index 00000000..8efa7306 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/examples/example-ae.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +#include +#include +#include + +/* Put event loop in the global scope, so it can be explicitly stopped */ +static aeEventLoop *loop; + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + aeStop(loop); + return; + } + + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + aeStop(loop); + return; + } + + printf("Disconnected...\n"); + aeStop(loop); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + loop = aeCreateEventLoop(64); + redisAeAttach(loop, c); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + aeMain(loop); + return 0; +} + diff --git a/ext/hiredis-vip-0.3.0/examples/example-glib.c b/ext/hiredis-vip-0.3.0/examples/example-glib.c new file mode 100644 index 00000000..d6e10f8e --- /dev/null +++ b/ext/hiredis-vip-0.3.0/examples/example-glib.c @@ -0,0 +1,73 @@ +#include + +#include +#include +#include + +static GMainLoop *mainloop; + +static void +connect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, + int status) +{ + if (status != REDIS_OK) { + g_printerr("Failed to connect: %s\n", ac->errstr); + g_main_loop_quit(mainloop); + } else { + g_printerr("Connected...\n"); + } +} + +static void +disconnect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, + int status) +{ + if (status != REDIS_OK) { + g_error("Failed to disconnect: %s", ac->errstr); + } else { + g_printerr("Disconnected...\n"); + g_main_loop_quit(mainloop); + } +} + +static void +command_cb(redisAsyncContext *ac, + gpointer r, + gpointer user_data G_GNUC_UNUSED) +{ + redisReply *reply = r; + + if (reply) { + g_print("REPLY: %s\n", reply->str); + } + + redisAsyncDisconnect(ac); +} + +gint +main (gint argc G_GNUC_UNUSED, + gchar *argv[] G_GNUC_UNUSED) +{ + redisAsyncContext *ac; + GMainContext *context = NULL; + GSource *source; + + ac = redisAsyncConnect("127.0.0.1", 6379); + if (ac->err) { + g_printerr("%s\n", ac->errstr); + exit(EXIT_FAILURE); + } + + source = redis_source_new(ac); + mainloop = g_main_loop_new(context, FALSE); + g_source_attach(source, context); + + redisAsyncSetConnectCallback(ac, connect_cb); + redisAsyncSetDisconnectCallback(ac, disconnect_cb); + redisAsyncCommand(ac, command_cb, NULL, "SET key 1234"); + redisAsyncCommand(ac, command_cb, NULL, "GET key"); + + g_main_loop_run(mainloop); + + return EXIT_SUCCESS; +} diff --git a/ext/hiredis-vip-0.3.0/examples/example-libev.c b/ext/hiredis-vip-0.3.0/examples/example-libev.c new file mode 100644 index 00000000..cc8b166e --- /dev/null +++ b/ext/hiredis-vip-0.3.0/examples/example-libev.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + redisLibevAttach(EV_DEFAULT_ c); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + ev_loop(EV_DEFAULT_ 0); + return 0; +} diff --git a/ext/hiredis-vip-0.3.0/examples/example-libevent.c b/ext/hiredis-vip-0.3.0/examples/example-libevent.c new file mode 100644 index 00000000..d333c22b --- /dev/null +++ b/ext/hiredis-vip-0.3.0/examples/example-libevent.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + struct event_base *base = event_base_new(); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + redisLibeventAttach(c,base); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + event_base_dispatch(base); + return 0; +} diff --git a/ext/hiredis-vip-0.3.0/examples/example-libuv.c b/ext/hiredis-vip-0.3.0/examples/example-libuv.c new file mode 100644 index 00000000..a5462d41 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/examples/example-libuv.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +#include +#include +#include + +void getCallback(redisAsyncContext *c, void *r, void *privdata) { + redisReply *reply = r; + if (reply == NULL) return; + printf("argv[%s]: %s\n", (char*)privdata, reply->str); + + /* Disconnect after receiving the reply to GET */ + redisAsyncDisconnect(c); +} + +void connectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Connected...\n"); +} + +void disconnectCallback(const redisAsyncContext *c, int status) { + if (status != REDIS_OK) { + printf("Error: %s\n", c->errstr); + return; + } + printf("Disconnected...\n"); +} + +int main (int argc, char **argv) { + signal(SIGPIPE, SIG_IGN); + uv_loop_t* loop = uv_default_loop(); + + redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); + if (c->err) { + /* Let *c leak for now... */ + printf("Error: %s\n", c->errstr); + return 1; + } + + redisLibuvAttach(c,loop); + redisAsyncSetConnectCallback(c,connectCallback); + redisAsyncSetDisconnectCallback(c,disconnectCallback); + redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); + redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/ext/hiredis-vip-0.3.0/examples/example.c b/ext/hiredis-vip-0.3.0/examples/example.c new file mode 100644 index 00000000..25226a80 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/examples/example.c @@ -0,0 +1,78 @@ +#include +#include +#include + +#include + +int main(int argc, char **argv) { + unsigned int j; + redisContext *c; + redisReply *reply; + const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; + int port = (argc > 2) ? atoi(argv[2]) : 6379; + + struct timeval timeout = { 1, 500000 }; // 1.5 seconds + c = redisConnectWithTimeout(hostname, port, timeout); + if (c == NULL || c->err) { + if (c) { + printf("Connection error: %s\n", c->errstr); + redisFree(c); + } else { + printf("Connection error: can't allocate redis context\n"); + } + exit(1); + } + + /* PING server */ + reply = redisCommand(c,"PING"); + printf("PING: %s\n", reply->str); + freeReplyObject(reply); + + /* Set a key */ + reply = redisCommand(c,"SET %s %s", "foo", "hello world"); + printf("SET: %s\n", reply->str); + freeReplyObject(reply); + + /* Set a key using binary safe API */ + reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); + printf("SET (binary API): %s\n", reply->str); + freeReplyObject(reply); + + /* Try a GET and two INCR */ + reply = redisCommand(c,"GET foo"); + printf("GET foo: %s\n", reply->str); + freeReplyObject(reply); + + reply = redisCommand(c,"INCR counter"); + printf("INCR counter: %lld\n", reply->integer); + freeReplyObject(reply); + /* again ... */ + reply = redisCommand(c,"INCR counter"); + printf("INCR counter: %lld\n", reply->integer); + freeReplyObject(reply); + + /* Create a list of numbers, from 0 to 9 */ + reply = redisCommand(c,"DEL mylist"); + freeReplyObject(reply); + for (j = 0; j < 10; j++) { + char buf[64]; + + snprintf(buf,64,"%d",j); + reply = redisCommand(c,"LPUSH mylist element-%s", buf); + freeReplyObject(reply); + } + + /* Let's check what we have inside the list */ + reply = redisCommand(c,"LRANGE mylist 0 -1"); + if (reply->type == REDIS_REPLY_ARRAY) { + for (j = 0; j < reply->elements; j++) { + printf("%u) %s\n", j, reply->element[j]->str); + } + } + freeReplyObject(reply); + + /* Disconnects and frees the context */ + redisFree(c); + + return 0; +} diff --git a/ext/hiredis-vip-0.3.0/fmacros.h b/ext/hiredis-vip-0.3.0/fmacros.h new file mode 100644 index 00000000..a3b1df03 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/fmacros.h @@ -0,0 +1,23 @@ +#ifndef __HIREDIS_FMACRO_H +#define __HIREDIS_FMACRO_H + +#if defined(__linux__) +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#define _DEFAULT_SOURCE +#endif + +#if defined(__sun__) +#define _POSIX_C_SOURCE 200112L +#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) +#define _XOPEN_SOURCE 600 +#else +#define _XOPEN_SOURCE +#endif + +#if __APPLE__ && __MACH__ +#define _OSX +#endif + +#endif diff --git a/ext/hiredis-vip-0.3.0/hiarray.c b/ext/hiredis-vip-0.3.0/hiarray.c new file mode 100644 index 00000000..cf742ecf --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hiarray.c @@ -0,0 +1,188 @@ +#include + +#include "hiutil.h" +#include "hiarray.h" + +struct hiarray * +hiarray_create(uint32_t n, size_t size) +{ + struct hiarray *a; + + ASSERT(n != 0 && size != 0); + + a = hi_alloc(sizeof(*a)); + if (a == NULL) { + return NULL; + } + + a->elem = hi_alloc(n * size); + if (a->elem == NULL) { + hi_free(a); + return NULL; + } + + a->nelem = 0; + a->size = size; + a->nalloc = n; + + return a; +} + +void +hiarray_destroy(struct hiarray *a) +{ + hiarray_deinit(a); + hi_free(a); +} + +int +hiarray_init(struct hiarray *a, uint32_t n, size_t size) +{ + ASSERT(n != 0 && size != 0); + + a->elem = hi_alloc(n * size); + if (a->elem == NULL) { + return HI_ENOMEM; + } + + a->nelem = 0; + a->size = size; + a->nalloc = n; + + return HI_OK; +} + +void +hiarray_deinit(struct hiarray *a) +{ + ASSERT(a->nelem == 0); + + if (a->elem != NULL) { + hi_free(a->elem); + } +} + +uint32_t +hiarray_idx(struct hiarray *a, void *elem) +{ + uint8_t *p, *q; + uint32_t off, idx; + + ASSERT(elem >= a->elem); + + p = a->elem; + q = elem; + off = (uint32_t)(q - p); + + ASSERT(off % (uint32_t)a->size == 0); + + idx = off / (uint32_t)a->size; + + return idx; +} + +void * +hiarray_push(struct hiarray *a) +{ + void *elem, *new; + size_t size; + + if (a->nelem == a->nalloc) { + + /* the array is full; allocate new array */ + size = a->size * a->nalloc; + new = hi_realloc(a->elem, 2 * size); + if (new == NULL) { + return NULL; + } + + a->elem = new; + a->nalloc *= 2; + } + + elem = (uint8_t *)a->elem + a->size * a->nelem; + a->nelem++; + + return elem; +} + +void * +hiarray_pop(struct hiarray *a) +{ + void *elem; + + ASSERT(a->nelem != 0); + + a->nelem--; + elem = (uint8_t *)a->elem + a->size * a->nelem; + + return elem; +} + +void * +hiarray_get(struct hiarray *a, uint32_t idx) +{ + void *elem; + + ASSERT(a->nelem != 0); + ASSERT(idx < a->nelem); + + elem = (uint8_t *)a->elem + (a->size * idx); + + return elem; +} + +void * +hiarray_top(struct hiarray *a) +{ + ASSERT(a->nelem != 0); + + return hiarray_get(a, a->nelem - 1); +} + +void +hiarray_swap(struct hiarray *a, struct hiarray *b) +{ + struct hiarray tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +/* + * Sort nelem elements of the array in ascending order based on the + * compare comparator. + */ +void +hiarray_sort(struct hiarray *a, hiarray_compare_t compare) +{ + ASSERT(a->nelem != 0); + + qsort(a->elem, a->nelem, a->size, compare); +} + +/* + * Calls the func once for each element in the array as long as func returns + * success. On failure short-circuits and returns the error status. + */ +int +hiarray_each(struct hiarray *a, hiarray_each_t func, void *data) +{ + uint32_t i, nelem; + + ASSERT(array_n(a) != 0); + ASSERT(func != NULL); + + for (i = 0, nelem = hiarray_n(a); i < nelem; i++) { + void *elem = hiarray_get(a, i); + rstatus_t status; + + status = func(elem, data); + if (status != HI_OK) { + return status; + } + } + + return HI_OK; +} diff --git a/ext/hiredis-vip-0.3.0/hiarray.h b/ext/hiredis-vip-0.3.0/hiarray.h new file mode 100644 index 00000000..fda3a4b8 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hiarray.h @@ -0,0 +1,56 @@ +#ifndef __HIARRAY_H_ +#define __HIARRAY_H_ + +#include + +typedef int (*hiarray_compare_t)(const void *, const void *); +typedef int (*hiarray_each_t)(void *, void *); + +struct hiarray { + uint32_t nelem; /* # element */ + void *elem; /* element */ + size_t size; /* element size */ + uint32_t nalloc; /* # allocated element */ +}; + +#define null_hiarray { 0, NULL, 0, 0 } + +static inline void +hiarray_null(struct hiarray *a) +{ + a->nelem = 0; + a->elem = NULL; + a->size = 0; + a->nalloc = 0; +} + +static inline void +hiarray_set(struct hiarray *a, void *elem, size_t size, uint32_t nalloc) +{ + a->nelem = 0; + a->elem = elem; + a->size = size; + a->nalloc = nalloc; +} + +static inline uint32_t +hiarray_n(const struct hiarray *a) +{ + return a->nelem; +} + +struct hiarray *hiarray_create(uint32_t n, size_t size); +void hiarray_destroy(struct hiarray *a); +int hiarray_init(struct hiarray *a, uint32_t n, size_t size); +void hiarray_deinit(struct hiarray *a); + +uint32_t hiarray_idx(struct hiarray *a, void *elem); +void *hiarray_push(struct hiarray *a); +void *hiarray_pop(struct hiarray *a); +void *hiarray_get(struct hiarray *a, uint32_t idx); +void *hiarray_top(struct hiarray *a); +void hiarray_swap(struct hiarray *a, struct hiarray *b); +void hiarray_sort(struct hiarray *a, hiarray_compare_t compare); +int hiarray_each(struct hiarray *a, hiarray_each_t func, void *data); + +#endif diff --git a/ext/hiredis-vip-0.3.0/hircluster.c b/ext/hiredis-vip-0.3.0/hircluster.c new file mode 100644 index 00000000..edf9cb2f --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hircluster.c @@ -0,0 +1,4747 @@ + +#include "fmacros.h" +#include +#include +#include +#include +#include + +#include "hircluster.h" +#include "hiutil.h" +#include "adlist.h" +#include "hiarray.h" +#include "command.h" +#include "dict.c" + +#define REDIS_COMMAND_CLUSTER_NODES "CLUSTER NODES" +#define REDIS_COMMAND_CLUSTER_SLOTS "CLUSTER SLOTS" + +#define REDIS_COMMAND_ASKING "ASKING" +#define REDIS_COMMAND_PING "PING" + +#define REDIS_PROTOCOL_ASKING "*1\r\n$6\r\nASKING\r\n" + +#define IP_PORT_SEPARATOR ":" + +#define CLUSTER_ADDRESS_SEPARATOR "," + +#define CLUSTER_DEFAULT_MAX_REDIRECT_COUNT 5 + +typedef struct cluster_async_data +{ + redisClusterAsyncContext *acc; + struct cmd *command; + redisClusterCallbackFn *callback; + int retry_count; + void *privdata; +}cluster_async_data; + +typedef enum CLUSTER_ERR_TYPE{ + CLUSTER_NOT_ERR = 0, + CLUSTER_ERR_MOVED, + CLUSTER_ERR_ASK, + CLUSTER_ERR_TRYAGAIN, + CLUSTER_ERR_CROSSSLOT, + CLUSTER_ERR_CLUSTERDOWN, + CLUSTER_ERR_SENTINEL +}CLUSTER_ERR_TYPE; + +static void cluster_node_deinit(cluster_node *node); +static void cluster_slot_destroy(cluster_slot *slot); +static void cluster_open_slot_destroy(copen_slot *oslot); + +void listClusterNodeDestructor(void *val) +{ + cluster_node_deinit(val); + + hi_free(val); +} + +void listClusterSlotDestructor(void *val) +{ + cluster_slot_destroy(val); +} + +unsigned int dictSdsHash(const void *key) { + return dictGenHashFunction((unsigned char*)key, sdslen((char*)key)); +} + +int dictSdsKeyCompare(void *privdata, const void *key1, + const void *key2) +{ + int l1,l2; + DICT_NOTUSED(privdata); + + l1 = sdslen((sds)key1); + l2 = sdslen((sds)key2); + if (l1 != l2) return 0; + return memcmp(key1, key2, l1) == 0; +} + +void dictSdsDestructor(void *privdata, void *val) +{ + DICT_NOTUSED(privdata); + + sdsfree(val); +} + +void dictClusterNodeDestructor(void *privdata, void *val) +{ + DICT_NOTUSED(privdata); + + cluster_node_deinit(val); + + hi_free(val); +} + +/* Cluster nodes hash table, mapping nodes + * name(437c719f50dc9d0745032f3b280ce7ecc40792ac) + * or addresses(1.2.3.4:6379) to clusterNode structures. + * Those nodes need destroy. + */ +dictType clusterNodesDictType = { + dictSdsHash, /* hash function */ + NULL, /* key dup */ + NULL, /* val dup */ + dictSdsKeyCompare, /* key compare */ + dictSdsDestructor, /* key destructor */ + dictClusterNodeDestructor /* val destructor */ +}; + +/* Cluster nodes hash table, mapping nodes + * name(437c719f50dc9d0745032f3b280ce7ecc40792ac) + * or addresses(1.2.3.4:6379) to clusterNode structures. + * Those nodes do not need destroy. + */ +dictType clusterNodesRefDictType = { + dictSdsHash, /* hash function */ + NULL, /* key dup */ + NULL, /* val dup */ + dictSdsKeyCompare, /* key compare */ + dictSdsDestructor, /* key destructor */ + NULL /* val destructor */ +}; + + +void listCommandFree(void *command) +{ + struct cmd *cmd = command; + command_destroy(cmd); +} + +/* Defined in hiredis.c */ +void __redisSetError(redisContext *c, int type, const char *str); + +/* Forward declaration of function in hiredis.c */ +int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); + +/* Helper function for the redisClusterCommand* family of functions. + * + * Write a formatted command to the output buffer. If the given context is + * blocking, immediately read the reply into the "reply" pointer. When the + * context is non-blocking, the "reply" pointer will not be used and the + * command is simply appended to the write buffer. + * + * Returns the reply when a reply was succesfully retrieved. Returns NULL + * otherwise. When NULL is returned in a blocking context, the error field + * in the context will be set. + */ +static void *__redisBlockForReply(redisContext *c) { + void *reply; + + if (c->flags & REDIS_BLOCK) { + if (redisGetReply(c,&reply) != REDIS_OK) + return NULL; + return reply; + } + return NULL; +} + + +/* ----------------------------------------------------------------------------- + * Key space handling + * -------------------------------------------------------------------------- */ + +/* We have 16384 hash slots. The hash slot of a given key is obtained + * as the least significant 14 bits of the crc16 of the key. + * + * However if the key contains the {...} pattern, only the part between + * { and } is hashed. This may be useful in the future to force certain + * keys to be in the same node (assuming no resharding is in progress). */ +static unsigned int keyHashSlot(char *key, int keylen) { + int s, e; /* start-end indexes of { and } */ + + for (s = 0; s < keylen; s++) + if (key[s] == '{') break; + + /* No '{' ? Hash the whole key. This is the base case. */ + if (s == keylen) return crc16(key,keylen) & 0x3FFF; + + /* '{' found? Check if we have the corresponding '}'. */ + for (e = s+1; e < keylen; e++) + if (key[e] == '}') break; + + /* No '}' or nothing betweeen {} ? Hash the whole key. */ + if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF; + + /* If we are here there is both a { and a } on its right. Hash + * what is in the middle between { and }. */ + return crc16(key+s+1,e-s-1) & 0x3FFF; +} + +static void __redisClusterSetError(redisClusterContext *cc, int type, const char *str) { + size_t len; + + if(cc == NULL){ + return; + } + + cc->err = type; + if (str != NULL) { + len = strlen(str); + len = len < (sizeof(cc->errstr)-1) ? len : (sizeof(cc->errstr)-1); + memcpy(cc->errstr,str,len); + cc->errstr[len] = '\0'; + } else { + /* Only REDIS_ERR_IO may lack a description! */ + assert(type == REDIS_ERR_IO); + __redis_strerror_r(errno, cc->errstr, sizeof(cc->errstr)); + } +} + +static int cluster_reply_error_type(redisReply *reply) +{ + + if(reply == NULL) + { + return REDIS_ERR; + } + + if(reply->type == REDIS_REPLY_ERROR) + { + if((int)strlen(REDIS_ERROR_MOVED) < reply->len && + strncmp(reply->str, REDIS_ERROR_MOVED, strlen(REDIS_ERROR_MOVED)) == 0) + { + return CLUSTER_ERR_MOVED; + } + else if((int)strlen(REDIS_ERROR_ASK) < reply->len && + strncmp(reply->str, REDIS_ERROR_ASK, strlen(REDIS_ERROR_ASK)) == 0) + { + return CLUSTER_ERR_ASK; + } + else if((int)strlen(REDIS_ERROR_TRYAGAIN) < reply->len && + strncmp(reply->str, REDIS_ERROR_TRYAGAIN, strlen(REDIS_ERROR_TRYAGAIN)) == 0) + { + return CLUSTER_ERR_TRYAGAIN; + } + else if((int)strlen(REDIS_ERROR_CROSSSLOT) < reply->len && + strncmp(reply->str, REDIS_ERROR_CROSSSLOT, strlen(REDIS_ERROR_CROSSSLOT)) == 0) + { + return CLUSTER_ERR_CROSSSLOT; + } + else if((int)strlen(REDIS_ERROR_CLUSTERDOWN) < reply->len && + strncmp(reply->str, REDIS_ERROR_CLUSTERDOWN, strlen(REDIS_ERROR_CLUSTERDOWN)) == 0) + { + return CLUSTER_ERR_CLUSTERDOWN; + } + else + { + return CLUSTER_ERR_SENTINEL; + } + } + + return CLUSTER_NOT_ERR; +} + +static int cluster_node_init(cluster_node *node) +{ + if(node == NULL){ + return REDIS_ERR; + } + + node->name = NULL; + node->addr = NULL; + node->host = NULL; + node->port = 0; + node->role = REDIS_ROLE_NULL; + node->myself = 0; + node->slaves = NULL; + node->con = NULL; + node->acon = NULL; + node->slots = NULL; + node->failure_count = 0; + node->data = NULL; + node->migrating = NULL; + node->importing = NULL; + + return REDIS_OK; +} + +static void cluster_node_deinit(cluster_node *node) +{ + copen_slot **oslot; + + if(node == NULL) + { + return; + } + + sdsfree(node->name); + sdsfree(node->addr); + sdsfree(node->host); + node->port = 0; + node->role = REDIS_ROLE_NULL; + node->myself = 0; + + if(node->con != NULL) + { + redisFree(node->con); + } + + if(node->acon != NULL) + { + redisAsyncFree(node->acon); + } + + if(node->slots != NULL) + { + listRelease(node->slots); + } + + if(node->slaves != NULL) + { + listRelease(node->slaves); + } + + if(node->migrating) + { + while(hiarray_n(node->migrating)) + { + oslot = hiarray_pop(node->migrating); + cluster_open_slot_destroy(*oslot); + } + + hiarray_destroy(node->migrating); + node->migrating = NULL; + } + + if(node->importing) + { + while(hiarray_n(node->importing)) + { + oslot = hiarray_pop(node->importing); + cluster_open_slot_destroy(*oslot); + } + + hiarray_destroy(node->importing); + node->importing = NULL; + } +} + +static int cluster_slot_init(cluster_slot *slot, cluster_node *node) +{ + slot->start = 0; + slot->end = 0; + slot->node = node; + + return REDIS_OK; +} + +static cluster_slot *cluster_slot_create(cluster_node *node) +{ + cluster_slot *slot; + + slot = hi_alloc(sizeof(*slot)); + if(slot == NULL){ + return NULL; + } + + cluster_slot_init(slot, node); + + if(node != NULL){ + ASSERT(node->role == REDIS_ROLE_MASTER); + if(node->slots == NULL){ + node->slots = listCreate(); + if(node->slots == NULL) + { + cluster_slot_destroy(slot); + return NULL; + } + + node->slots->free = listClusterSlotDestructor; + } + + listAddNodeTail(node->slots, slot); + } + + return slot; +} + +static int cluster_slot_ref_node(cluster_slot * slot, cluster_node *node) +{ + if(slot == NULL || node == NULL){ + return REDIS_ERR; + } + + + if(node->role != REDIS_ROLE_MASTER){ + return REDIS_ERR; + } + + if(node->slots == NULL){ + node->slots = listCreate(); + if(node->slots == NULL) + { + return REDIS_ERR; + } + + node->slots->free = listClusterSlotDestructor; + } + + listAddNodeTail(node->slots, slot); + slot->node = node; + + return REDIS_OK; +} + +static void cluster_slot_destroy(cluster_slot *slot) +{ + slot->start = 0; + slot->end = 0; + slot->node = NULL; + + hi_free(slot); +} + +static copen_slot *cluster_open_slot_create(uint32_t slot_num, int migrate, + sds remote_name, cluster_node *node) +{ + copen_slot *oslot; + + oslot = hi_alloc(sizeof(*oslot)); + if(oslot == NULL){ + return NULL; + } + + oslot->slot_num = 0; + oslot->migrate = 0; + oslot->node = NULL; + oslot->remote_name = NULL; + + oslot->slot_num = slot_num; + oslot->migrate = migrate; + oslot->node = node; + oslot->remote_name = sdsdup(remote_name); + + return oslot; +} + +static void cluster_open_slot_destroy(copen_slot *oslot) +{ + oslot->slot_num = 0; + oslot->migrate = 0; + oslot->node = NULL; + + if(oslot->remote_name != NULL){ + sdsfree(oslot->remote_name); + oslot->remote_name = NULL; + } + + hi_free(oslot); +} + +/** + * Return a new node with the "cluster slots" command reply. + */ +static cluster_node *node_get_with_slots( + redisClusterContext *cc, redisReply *host_elem, + redisReply *port_elem, uint8_t role) +{ + cluster_node *node = NULL; + + if(host_elem == NULL || port_elem == NULL){ + return NULL; + } + + if(host_elem->type != REDIS_REPLY_STRING || + host_elem->len <= 0){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "node ip is not string."); + goto error; + } + + if(port_elem->type != REDIS_REPLY_INTEGER || + port_elem->integer <= 0){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "node port is not integer."); + goto error; + } + + if(!hi_valid_port((int)port_elem->integer)){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "node port is not valid."); + goto error; + } + + node = hi_alloc(sizeof(cluster_node)); + if(node == NULL){ + __redisClusterSetError(cc, + REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + cluster_node_init(node); + + if(role == REDIS_ROLE_MASTER){ + node->slots = listCreate(); + if(node->slots == NULL){ + hi_free(node); + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "slots for node listCreate error"); + goto error; + } + + node->slots->free = listClusterSlotDestructor; + } + + node->name = NULL; + node->addr = sdsnewlen(host_elem->str, host_elem->len); + node->addr = sdscatfmt(node->addr, ":%i", port_elem->integer); + + node->host = sdsnewlen(host_elem->str, host_elem->len); + node->port = (int)port_elem->integer; + node->role = role; + + return node; + +error: + + if(node != NULL){ + hi_free(node); + } + + return NULL; +} + +/** + * Return a new node with the "cluster nodes" command reply. + */ +static cluster_node *node_get_with_nodes( + redisClusterContext *cc, + sds *node_infos, int info_count, uint8_t role) +{ + sds *ip_port = NULL; + int count_ip_port = 0; + cluster_node *node; + + if(info_count < 8) + { + return NULL; + } + + node = hi_alloc(sizeof(cluster_node)); + if(node == NULL) + { + __redisClusterSetError(cc, + REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + cluster_node_init(node); + + if(role == REDIS_ROLE_MASTER) + { + node->slots = listCreate(); + if(node->slots == NULL) + { + hi_free(node); + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "slots for node listCreate error"); + goto error; + } + + node->slots->free = listClusterSlotDestructor; + } + + node->name = node_infos[0]; + node->addr = node_infos[1]; + + ip_port = sdssplitlen(node_infos[1], sdslen(node_infos[1]), + IP_PORT_SEPARATOR, strlen(IP_PORT_SEPARATOR), &count_ip_port); + if(ip_port == NULL || count_ip_port != 2) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "split ip port error"); + goto error; + } + node->host = ip_port[0]; + node->port = hi_atoi(ip_port[1], sdslen(ip_port[1])); + node->role = role; + + sdsfree(ip_port[1]); + free(ip_port); + + node_infos[0] = NULL; + node_infos[1] = NULL; + + return node; + +error: + if(ip_port != NULL) + { + sdsfreesplitres(ip_port, count_ip_port); + } + + if(node != NULL) + { + hi_free(node); + } + + return NULL; +} + +static void cluster_nodes_swap_ctx(dict *nodes_f, dict *nodes_t) +{ + dictIterator *di; + dictEntry *de_f, *de_t; + cluster_node *node_f, *node_t; + redisContext *c; + redisAsyncContext *ac; + + if(nodes_f == NULL || nodes_t == NULL){ + return; + } + + di = dictGetIterator(nodes_t); + while((de_t = dictNext(di)) != NULL){ + node_t = dictGetEntryVal(de_t); + if(node_t == NULL){ + continue; + } + + de_f = dictFind(nodes_f, node_t->addr); + if(de_f == NULL){ + continue; + } + + node_f = dictGetEntryVal(de_f); + if(node_f->con != NULL){ + c = node_f->con; + node_f->con = node_t->con; + node_t->con = c; + } + + if(node_f->acon != NULL){ + ac = node_f->acon; + node_f->acon = node_t->acon; + node_t->acon = ac; + + node_t->acon->data = node_t; + if (node_f->acon) + node_f->acon->data = node_f; + } + } + + dictReleaseIterator(di); + +} + +static int +cluster_slot_start_cmp(const void *t1, const void *t2) +{ + const cluster_slot **s1 = t1, **s2 = t2; + + return (*s1)->start > (*s2)->start?1:-1; +} + +static int +cluster_master_slave_mapping_with_name(redisClusterContext *cc, + dict **nodes, cluster_node *node, sds master_name) +{ + int ret; + dictEntry *di; + cluster_node *node_old; + listNode *lnode; + + if(node == NULL || master_name == NULL) + { + return REDIS_ERR; + } + + if(*nodes == NULL) + { + *nodes = dictCreate( + &clusterNodesRefDictType, NULL); + } + + di = dictFind(*nodes, master_name); + if(di == NULL) + { + ret = dictAdd(*nodes, + sdsnewlen(master_name, sdslen(master_name)), node); + if(ret != DICT_OK) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "the address already exists in the nodes"); + return REDIS_ERR; + } + + } + else + { + node_old = dictGetEntryVal(di); + if(node_old == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "dict get value null"); + return REDIS_ERR; + } + + if(node->role == REDIS_ROLE_MASTER && + node_old->role == REDIS_ROLE_MASTER) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "two masters have the same name"); + return REDIS_ERR; + } + else if(node->role == REDIS_ROLE_MASTER + && node_old->role == REDIS_ROLE_SLAVE) + { + if(node->slaves == NULL) + { + node->slaves = listCreate(); + if(node->slaves == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Out of memory"); + return REDIS_ERR; + } + + node->slaves->free = + listClusterNodeDestructor; + } + + if(node_old->slaves != NULL) + { + node_old->slaves->free = NULL; + while(listLength(node_old->slaves) > 0) + { + lnode = listFirst(node_old->slaves); + listAddNodeHead(node->slaves, lnode->value); + listDelNode(node_old->slaves, lnode); + } + listRelease(node_old->slaves); + node_old->slaves = NULL; + } + + listAddNodeHead(node->slaves, node_old); + + dictSetHashVal(*nodes, di, node); + } + else if(node->role == REDIS_ROLE_SLAVE) + { + if(node_old->slaves == NULL) + { + node_old->slaves = listCreate(); + if(node_old->slaves == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Out of memory"); + return REDIS_ERR; + } + + node_old->slaves->free = + listClusterNodeDestructor; + } + + listAddNodeTail(node_old->slaves, node); + } + else + { + NOT_REACHED(); + } + } + + return REDIS_OK; +} + +/** + * Parse the "cluster slots" command reply to nodes dict. + */ +dict * +parse_cluster_slots(redisClusterContext *cc, + redisReply *reply, int flags) +{ + int ret; + cluster_slot *slot = NULL; + dict *nodes = NULL; + dictEntry *den; + redisReply *elem_slots; + redisReply *elem_slots_begin, *elem_slots_end; + redisReply *elem_nodes; + redisReply *elem_ip, *elem_port; + cluster_node *master = NULL, *slave; + sds address; + uint32_t i, idx; + + if(reply == NULL){ + return NULL; + } + + nodes = dictCreate(&clusterNodesDictType, NULL); + if(nodes == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OOM, + "out of memory"); + goto error; + } + + if(reply->type != REDIS_REPLY_ARRAY || reply->elements <= 0){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "reply is not an array."); + goto error; + } + + for(i = 0; i < reply->elements; i ++){ + elem_slots = reply->element[i]; + if(elem_slots->type != REDIS_REPLY_ARRAY || + elem_slots->elements < 3){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "first sub_reply is not an array."); + goto error; + } + + slot = cluster_slot_create(NULL); + if(slot == NULL){ + __redisClusterSetError(cc, REDIS_ERR_OOM, + "Slot create failed: out of memory."); + goto error; + } + + //one slots region + for(idx = 0; idx < elem_slots->elements; idx ++){ + if(idx == 0){ + elem_slots_begin = elem_slots->element[idx]; + if(elem_slots_begin->type != REDIS_REPLY_INTEGER){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "slot begin is not an integer."); + goto error; + } + slot->start = (int)(elem_slots_begin->integer); + }else if(idx == 1){ + elem_slots_end = elem_slots->element[idx]; + if(elem_slots_end->type != REDIS_REPLY_INTEGER){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "slot end is not an integer."); + goto error; + } + + slot->end = (int)(elem_slots_end->integer); + + if(slot->start > slot->end){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "slot begin is bigger than slot end."); + goto error; + } + }else{ + elem_nodes = elem_slots->element[idx]; + if(elem_nodes->type != REDIS_REPLY_ARRAY || + elem_nodes->elements != 3){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "nodes sub_reply is not an correct array."); + goto error; + } + + elem_ip = elem_nodes->element[0]; + elem_port = elem_nodes->element[1]; + + if(elem_ip == NULL || elem_port == NULL || + elem_ip->type != REDIS_REPLY_STRING || + elem_port->type != REDIS_REPLY_INTEGER){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Command(cluster slots) reply error: " + "master ip or port is not correct."); + goto error; + } + + //this is master. + if(idx == 2){ + address = sdsnewlen(elem_ip->str, elem_ip->len); + address = sdscatfmt(address, ":%i", elem_port->integer); + + den = dictFind(nodes, address); + //master already exits, break to the next slots region. + if(den != NULL){ + sdsfree(address); + + master = dictGetEntryVal(den); + ret = cluster_slot_ref_node(slot, master); + if(ret != REDIS_OK){ + __redisClusterSetError(cc, REDIS_ERR_OOM, + "Slot ref node failed: out of memory."); + goto error; + } + + slot = NULL; + break; + } + + sdsfree(address); + master = node_get_with_slots(cc, elem_ip, + elem_port, REDIS_ROLE_MASTER); + if(master == NULL){ + goto error; + } + + ret = dictAdd(nodes, + sdsnewlen(master->addr, sdslen(master->addr)), master); + if(ret != DICT_OK){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "The address already exists in the nodes"); + cluster_node_deinit(master); + hi_free(master); + goto error; + } + + ret = cluster_slot_ref_node(slot, master); + if(ret != REDIS_OK){ + __redisClusterSetError(cc, REDIS_ERR_OOM, + "Slot ref node failed: out of memory."); + goto error; + } + + slot = NULL; + }else if(flags & HIRCLUSTER_FLAG_ADD_SLAVE){ + slave = node_get_with_slots(cc, elem_ip, + elem_port, REDIS_ROLE_SLAVE); + if(slave == NULL){ + goto error; + } + + if(master->slaves == NULL){ + master->slaves = listCreate(); + if(master->slaves == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Out of memory"); + cluster_node_deinit(slave); + goto error; + } + + master->slaves->free = + listClusterNodeDestructor; + } + + listAddNodeTail(master->slaves, slave); + } + } + } + } + + return nodes; + +error: + + if(nodes != NULL){ + dictRelease(nodes); + } + + if(slot != NULL){ + cluster_slot_destroy(slot); + } + + return NULL; +} + +/** + * Parse the "cluster nodes" command reply to nodes dict. + */ +dict * +parse_cluster_nodes(redisClusterContext *cc, + char *str, int str_len, int flags) +{ + int ret; + dict *nodes = NULL; + dict *nodes_name = NULL; + cluster_node *master, *slave; + cluster_slot *slot; + char *pos, *start, *end, *line_start, *line_end; + char *role; + int role_len; + uint8_t myself = 0; + int slot_start, slot_end; + sds *part = NULL, *slot_start_end = NULL; + int count_part = 0, count_slot_start_end = 0; + int k; + int len; + + nodes = dictCreate(&clusterNodesDictType, NULL); + if(nodes == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OOM, + "out of memory"); + goto error; + } + + start = str; + end = start + str_len; + + line_start = start; + + for(pos = start; pos < end; pos ++){ + if(*pos == '\n'){ + line_end = pos - 1; + len = line_end - line_start; + + part = sdssplitlen(line_start, len + 1, " ", 1, &count_part); + + if(part == NULL || count_part < 8){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "split cluster nodes error"); + goto error; + } + + //the address string is ":0", skip this node. + if(sdslen(part[1]) == 2 && strcmp(part[1], ":0") == 0){ + sdsfreesplitres(part, count_part); + count_part = 0; + part = NULL; + + start = pos + 1; + line_start = start; + pos = start; + + continue; + } + + if(sdslen(part[2]) >= 7 && memcmp(part[2], "myself,", 7) == 0){ + role_len = sdslen(part[2]) - 7; + role = part[2] + 7; + myself = 1; + }else{ + role_len = sdslen(part[2]); + role = part[2]; + } + + //add master node + if(role_len >= 6 && memcmp(role, "master", 6) == 0){ + if(count_part < 8){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Master node parts number error: less than 8."); + goto error; + } + + master = node_get_with_nodes(cc, + part, count_part, REDIS_ROLE_MASTER); + if(master == NULL){ + goto error; + } + + ret = dictAdd(nodes, + sdsnewlen(master->addr, sdslen(master->addr)), master); + if(ret != DICT_OK){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "The address already exists in the nodes"); + cluster_node_deinit(master); + hi_free(master); + goto error; + } + + if(flags & HIRCLUSTER_FLAG_ADD_SLAVE){ + ret = cluster_master_slave_mapping_with_name(cc, + &nodes_name, master, master->name); + if(ret != REDIS_OK){ + cluster_node_deinit(master); + hi_free(master); + goto error; + } + } + + if(myself) master->myself = 1; + + for(k = 8; k < count_part; k ++){ + slot_start_end = sdssplitlen(part[k], + sdslen(part[k]), "-", 1, &count_slot_start_end); + + if(slot_start_end == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "split slot start end error(NULL)"); + goto error; + }else if(count_slot_start_end == 1){ + slot_start = + hi_atoi(slot_start_end[0], sdslen(slot_start_end[0])); + slot_end = slot_start; + }else if(count_slot_start_end == 2){ + slot_start = + hi_atoi(slot_start_end[0], sdslen(slot_start_end[0]));; + slot_end = + hi_atoi(slot_start_end[1], sdslen(slot_start_end[1]));; + }else{ + //add open slot for master + if(flags & HIRCLUSTER_FLAG_ADD_OPENSLOT && + count_slot_start_end == 3 && + sdslen(slot_start_end[0]) > 1 && + sdslen(slot_start_end[1]) == 1 && + sdslen(slot_start_end[2]) > 1 && + slot_start_end[0][0] == '[' && + slot_start_end[2][sdslen(slot_start_end[2])-1] == ']'){ + + copen_slot *oslot, **oslot_elem; + + sdsrange(slot_start_end[0], 1, -1); + sdsrange(slot_start_end[2], 0, -2); + + if(slot_start_end[1][0] == '>'){ + oslot = cluster_open_slot_create( + hi_atoi(slot_start_end[0], + sdslen(slot_start_end[0])), + 1, slot_start_end[2], master); + if(oslot == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "create open slot error"); + goto error; + } + + if(master->migrating == NULL){ + master->migrating = hiarray_create(1, sizeof(oslot)); + if(master->migrating == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "create migrating array error"); + cluster_open_slot_destroy(oslot); + goto error; + } + } + + oslot_elem = hiarray_push(master->migrating); + if(oslot_elem == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Push migrating array error: out of memory"); + cluster_open_slot_destroy(oslot); + goto error; + } + + *oslot_elem = oslot; + }else if(slot_start_end[1][0] == '<'){ + oslot = cluster_open_slot_create(hi_atoi(slot_start_end[0], + sdslen(slot_start_end[0])), 0, slot_start_end[2], + master); + if(oslot == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "create open slot error"); + goto error; + } + + if(master->importing == NULL){ + master->importing = hiarray_create(1, sizeof(oslot)); + if(master->importing == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "create migrating array error"); + cluster_open_slot_destroy(oslot); + goto error; + } + } + + oslot_elem = hiarray_push(master->importing); + if(oslot_elem == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "push migrating array error: out of memory"); + cluster_open_slot_destroy(oslot); + goto error; + } + + *oslot_elem = oslot; + } + } + + slot_start = -1; + slot_end = -1; + } + + sdsfreesplitres(slot_start_end, count_slot_start_end); + count_slot_start_end = 0; + slot_start_end = NULL; + + if(slot_start < 0 || slot_end < 0 || + slot_start > slot_end || slot_end >= REDIS_CLUSTER_SLOTS){ + continue; + } + + slot = cluster_slot_create(master); + if(slot == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Out of memory"); + goto error; + } + + slot->start = (uint32_t)slot_start; + slot->end = (uint32_t)slot_end; + } + + } + //add slave node + else if((flags & HIRCLUSTER_FLAG_ADD_SLAVE) && + (role_len >= 5 && memcmp(role, "slave", 5) == 0)){ + slave = node_get_with_nodes(cc, part, + count_part, REDIS_ROLE_SLAVE); + if(slave == NULL){ + goto error; + } + + ret = cluster_master_slave_mapping_with_name(cc, + &nodes_name, slave, part[3]); + if(ret != REDIS_OK){ + cluster_node_deinit(slave); + hi_free(slave); + goto error; + } + + if(myself) slave->myself = 1; + } + + if(myself == 1){ + myself = 0; + } + + sdsfreesplitres(part, count_part); + count_part = 0; + part = NULL; + + start = pos + 1; + line_start = start; + pos = start; + } + } + + if(nodes_name != NULL){ + dictRelease(nodes_name); + } + + return nodes; + +error: + + if(part != NULL){ + sdsfreesplitres(part, count_part); + count_part = 0; + part = NULL; + } + + if(slot_start_end != NULL){ + sdsfreesplitres(slot_start_end, count_slot_start_end); + count_slot_start_end = 0; + slot_start_end = NULL; + } + + if(nodes != NULL){ + dictRelease(nodes); + } + + if(nodes_name != NULL){ + dictRelease(nodes_name); + } + + return NULL; +} + +/** + * Update route with the "cluster nodes" or "cluster slots" command reply. + */ +static int +cluster_update_route_by_addr(redisClusterContext *cc, + const char *ip, int port) +{ + redisContext *c = NULL; + redisReply *reply = NULL; + dict *nodes = NULL; + struct hiarray *slots = NULL; + cluster_node *master; + cluster_slot *slot, **slot_elem; + dictIterator *dit = NULL; + dictEntry *den; + listIter *lit = NULL; + listNode *lnode; + cluster_node *table[REDIS_CLUSTER_SLOTS]; + uint32_t j, k; + + if(cc == NULL){ + return REDIS_ERR; + } + + if(ip == NULL || port <= 0){ + __redisClusterSetError(cc, + REDIS_ERR_OTHER,"Ip or port error!"); + goto error; + } + + if(cc->timeout){ + c = redisConnectWithTimeout(ip, port, *cc->timeout); + }else{ + c = redisConnect(ip, port); + } + + if (c == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Init redis context error(return NULL)"); + goto error; + }else if(c->err){ + __redisClusterSetError(cc,c->err,c->errstr); + goto error; + } + + if(cc->flags & HIRCLUSTER_FLAG_ROUTE_USE_SLOTS){ + reply = redisCommand(c, REDIS_COMMAND_CLUSTER_SLOTS); + if(reply == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Command(cluster slots) reply error(NULL)."); + goto error; + }else if(reply->type != REDIS_REPLY_ARRAY){ + if(reply->type == REDIS_REPLY_ERROR){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + reply->str); + }else{ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Command(cluster slots) reply error: type is not array."); + } + + goto error; + } + + nodes = parse_cluster_slots(cc, reply, cc->flags); + }else{ + reply = redisCommand(c, REDIS_COMMAND_CLUSTER_NODES); + if(reply == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Command(cluster nodes) reply error(NULL)."); + goto error; + }else if(reply->type != REDIS_REPLY_STRING){ + if(reply->type == REDIS_REPLY_ERROR){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + reply->str); + }else{ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Command(cluster nodes) reply error: type is not string."); + } + + goto error; + } + + nodes = parse_cluster_nodes(cc, reply->str, reply->len, cc->flags); + } + + if(nodes == NULL){ + goto error; + } + + memset(table, 0, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); + + slots = hiarray_create(dictSize(nodes), sizeof(cluster_slot*)); + if(slots == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "Slots array create failed: out of memory"); + goto error; + } + + dit = dictGetIterator(nodes); + if(dit == NULL){ + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Dict get iterator failed: out of memory"); + goto error; + } + + while((den = dictNext(dit))){ + master = dictGetEntryVal(den); + if(master->role != REDIS_ROLE_MASTER){ + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Node role must be master"); + goto error; + } + + if(master->slots == NULL){ + continue; + } + + lit = listGetIterator(master->slots, AL_START_HEAD); + if(lit == NULL){ + __redisClusterSetError(cc, REDIS_ERR_OOM, + "List get iterator failed: out of memory"); + goto error; + } + + while((lnode = listNext(lit))){ + slot = listNodeValue(lnode); + if(slot->start > slot->end || + slot->end >= REDIS_CLUSTER_SLOTS){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Slot region for node is error"); + goto error; + } + + slot_elem = hiarray_push(slots); + *slot_elem = slot; + } + + listReleaseIterator(lit); + } + + dictReleaseIterator(dit); + + hiarray_sort(slots, cluster_slot_start_cmp); + for(j = 0; j < hiarray_n(slots); j ++){ + slot_elem = hiarray_get(slots, j); + + for(k = (*slot_elem)->start; k <= (*slot_elem)->end; k ++){ + if(table[k] != NULL){ + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "Diffent node hold a same slot"); + goto error; + } + + table[k] = (*slot_elem)->node; + } + } + + cluster_nodes_swap_ctx(cc->nodes, nodes); + if(cc->nodes != NULL){ + dictRelease(cc->nodes); + cc->nodes = NULL; + } + cc->nodes = nodes; + + if(cc->slots != NULL) + { + cc->slots->nelem = 0; + hiarray_destroy(cc->slots); + cc->slots = NULL; + } + cc->slots = slots; + + memcpy(cc->table, table, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); + cc->route_version ++; + + freeReplyObject(reply); + + if(c != NULL){ + redisFree(c); + } + + return REDIS_OK; + +error: + + if(dit != NULL){ + dictReleaseIterator(dit); + } + + if(lit != NULL){ + listReleaseIterator(lit); + } + + if(slots != NULL) + { + if(slots == cc->slots) + { + cc->slots = NULL; + } + + slots->nelem = 0; + hiarray_destroy(slots); + } + + if(nodes != NULL){ + if(nodes == cc->nodes){ + cc->nodes = NULL; + } + + dictRelease(nodes); + } + + if(reply != NULL){ + freeReplyObject(reply); + reply = NULL; + } + + if(c != NULL){ + redisFree(c); + } + + return REDIS_ERR; +} + + +/** + * Update route with the "cluster nodes" command reply. + */ +static int +cluster_update_route_with_nodes_old(redisClusterContext *cc, + const char *ip, int port) +{ + int ret; + redisContext *c = NULL; + redisReply *reply = NULL; + struct hiarray *slots = NULL; + dict *nodes = NULL; + dict *nodes_name = NULL; + cluster_node *master, *slave; + cluster_slot **slot; + char *pos, *start, *end, *line_start, *line_end; + char *role; + int role_len; + uint8_t myself = 0; + int slot_start, slot_end; + sds *part = NULL, *slot_start_end = NULL; + int count_part = 0, count_slot_start_end = 0; + int j, k; + int len; + cluster_node *table[REDIS_CLUSTER_SLOTS] = {NULL}; + + if(cc == NULL) + { + return REDIS_ERR; + } + + if(ip == NULL || port <= 0) + { + __redisClusterSetError(cc, + REDIS_ERR_OTHER,"ip or port error!"); + goto error; + } + + if(cc->timeout) + { + c = redisConnectWithTimeout(ip, port, *cc->timeout); + } + else + { + c = redisConnect(ip, port); + } + + if (c == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "init redis context error(return NULL)"); + goto error; + } + else if(c->err) + { + __redisClusterSetError(cc,c->err,c->errstr); + goto error; + } + + reply = redisCommand(c, REDIS_COMMAND_CLUSTER_NODES); + + if(reply == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "command(cluster nodes) reply error(NULL)"); + goto error; + } + else if(reply->type != REDIS_REPLY_STRING) + { + if(reply->type == REDIS_REPLY_ERROR) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + reply->str); + } + else + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "command(cluster nodes) reply error(type is not string)"); + } + + goto error; + } + + nodes = dictCreate(&clusterNodesDictType, NULL); + + slots = hiarray_create(10, sizeof(cluster_slot*)); + if(slots == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "array create error"); + goto error; + } + + start = reply->str; + end = start + reply->len; + + line_start = start; + + for(pos = start; pos < end; pos ++) + { + if(*pos == '\n') + { + line_end = pos - 1; + len = line_end - line_start; + + part = sdssplitlen(line_start, len + 1, " ", 1, &count_part); + + if(part == NULL || count_part < 8) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "split cluster nodes error"); + goto error; + } + + //the address string is ":0", skip this node. + if(sdslen(part[1]) == 2 && strcmp(part[1], ":0") == 0) + { + sdsfreesplitres(part, count_part); + count_part = 0; + part = NULL; + + start = pos + 1; + line_start = start; + pos = start; + + continue; + } + + if(sdslen(part[2]) >= 7 && memcmp(part[2], "myself,", 7) == 0) + { + role_len = sdslen(part[2]) - 7; + role = part[2] + 7; + myself = 1; + } + else + { + role_len = sdslen(part[2]); + role = part[2]; + } + + //add master node + if(role_len >= 6 && memcmp(role, "master", 6) == 0) + { + if(count_part < 8) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "master node part number error"); + goto error; + } + + master = node_get_with_nodes(cc, + part, count_part, REDIS_ROLE_MASTER); + if(master == NULL) + { + goto error; + } + + ret = dictAdd(nodes, + sdsnewlen(master->addr, sdslen(master->addr)), master); + if(ret != DICT_OK) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "the address already exists in the nodes"); + cluster_node_deinit(master); + hi_free(master); + goto error; + } + + if(cc->flags & HIRCLUSTER_FLAG_ADD_SLAVE) + { + ret = cluster_master_slave_mapping_with_name(cc, + &nodes_name, master, master->name); + if(ret != REDIS_OK) + { + cluster_node_deinit(master); + hi_free(master); + goto error; + } + } + + if(myself == 1) + { + master->con = c; + c = NULL; + } + + for(k = 8; k < count_part; k ++) + { + slot_start_end = sdssplitlen(part[k], + sdslen(part[k]), "-", 1, &count_slot_start_end); + + if(slot_start_end == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "split slot start end error(NULL)"); + goto error; + } + else if(count_slot_start_end == 1) + { + slot_start = + hi_atoi(slot_start_end[0], sdslen(slot_start_end[0])); + slot_end = slot_start; + } + else if(count_slot_start_end == 2) + { + slot_start = + hi_atoi(slot_start_end[0], sdslen(slot_start_end[0]));; + slot_end = + hi_atoi(slot_start_end[1], sdslen(slot_start_end[1]));; + } + else + { + slot_start = -1; + slot_end = -1; + } + + sdsfreesplitres(slot_start_end, count_slot_start_end); + count_slot_start_end = 0; + slot_start_end = NULL; + + if(slot_start < 0 || slot_end < 0 || + slot_start > slot_end || slot_end >= REDIS_CLUSTER_SLOTS) + { + continue; + } + + for(j = slot_start; j <= slot_end; j ++) + { + if(table[j] != NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "diffent node hold a same slot"); + goto error; + } + table[j] = master; + } + + slot = hiarray_push(slots); + if(slot == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "slot push in array error"); + goto error; + } + + *slot = cluster_slot_create(master); + if(*slot == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM, + "Out of memory"); + goto error; + } + + (*slot)->start = (uint32_t)slot_start; + (*slot)->end = (uint32_t)slot_end; + } + + } + //add slave node + else if((cc->flags & HIRCLUSTER_FLAG_ADD_SLAVE) && + (role_len >= 5 && memcmp(role, "slave", 5) == 0)) + { + slave = node_get_with_nodes(cc, part, + count_part, REDIS_ROLE_SLAVE); + if(slave == NULL) + { + goto error; + } + + ret = cluster_master_slave_mapping_with_name(cc, + &nodes_name, slave, part[3]); + if(ret != REDIS_OK) + { + cluster_node_deinit(slave); + hi_free(slave); + goto error; + } + + if(myself == 1) + { + slave->con = c; + c = NULL; + } + } + + if(myself == 1) + { + myself = 0; + } + + sdsfreesplitres(part, count_part); + count_part = 0; + part = NULL; + + start = pos + 1; + line_start = start; + pos = start; + } + } + + if(cc->slots != NULL) + { + cc->slots->nelem = 0; + hiarray_destroy(cc->slots); + cc->slots = NULL; + } + cc->slots = slots; + + cluster_nodes_swap_ctx(cc->nodes, nodes); + + if(cc->nodes != NULL) + { + dictRelease(cc->nodes); + cc->nodes = NULL; + } + cc->nodes = nodes; + + hiarray_sort(cc->slots, cluster_slot_start_cmp); + + memcpy(cc->table, table, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); + cc->route_version ++; + + freeReplyObject(reply); + + if(c != NULL) + { + redisFree(c); + } + + if(nodes_name != NULL) + { + dictRelease(nodes_name); + } + + return REDIS_OK; + +error: + + if(part != NULL) + { + sdsfreesplitres(part, count_part); + count_part = 0; + part = NULL; + } + + if(slot_start_end != NULL) + { + sdsfreesplitres(slot_start_end, count_slot_start_end); + count_slot_start_end = 0; + slot_start_end = NULL; + } + + if(slots != NULL) + { + if(slots == cc->slots) + { + cc->slots = NULL; + } + + slots->nelem = 0; + hiarray_destroy(slots); + } + + if(nodes != NULL) + { + if(nodes == cc->nodes) + { + cc->nodes = NULL; + } + + dictRelease(nodes); + } + + if(nodes_name != NULL) + { + dictRelease(nodes_name); + } + + if(reply != NULL) + { + freeReplyObject(reply); + reply = NULL; + } + + if(c != NULL) + { + redisFree(c); + } + + return REDIS_ERR; +} + +int +cluster_update_route(redisClusterContext *cc) +{ + int ret; + int flag_err_not_set = 1; + cluster_node *node; + dictIterator *it; + dictEntry *de; + + if(cc == NULL) + { + return REDIS_ERR; + } + + if(cc->ip != NULL && cc->port > 0) + { + ret = cluster_update_route_by_addr(cc, cc->ip, cc->port); + if(ret == REDIS_OK) + { + return REDIS_OK; + } + + flag_err_not_set = 0; + } + + if(cc->nodes == NULL) + { + if(flag_err_not_set) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "no server address"); + } + + return REDIS_ERR; + } + + it = dictGetIterator(cc->nodes); + while ((de = dictNext(it)) != NULL) + { + node = dictGetEntryVal(de); + if(node == NULL || node->host == NULL || node->port < 0) + { + continue; + } + + ret = cluster_update_route_by_addr(cc, node->host, node->port); + if(ret == REDIS_OK) + { + if(cc->err) + { + cc->err = 0; + memset(cc->errstr, '\0', strlen(cc->errstr)); + } + + dictReleaseIterator(it); + return REDIS_OK; + } + + flag_err_not_set = 0; + } + + dictReleaseIterator(it); + + if(flag_err_not_set) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "no valid server address"); + } + + return REDIS_ERR; +} + +static void print_cluster_node_list(redisClusterContext *cc) +{ + dictIterator *di = NULL; + dictEntry *de; + listIter *it; + listNode *ln; + cluster_node *master, *slave; + hilist *slaves; + + if(cc == NULL) + { + return; + } + + di = dictGetIterator(cc->nodes); + + printf("name\taddress\trole\tslaves\n"); + + while((de = dictNext(di)) != NULL) { + master = dictGetEntryVal(de); + + printf("%s\t%s\t%d\t%s\n",master->name, master->addr, + master->role, master->slaves?"hava":"null"); + + slaves = master->slaves; + if(slaves == NULL) + { + continue; + } + + it = listGetIterator(slaves, AL_START_HEAD); + while((ln = listNext(it)) != NULL) + { + slave = listNodeValue(ln); + printf("%s\t%s\t%d\t%s\n",slave->name, slave->addr, + slave->role, slave->slaves?"hava":"null"); + } + + listReleaseIterator(it); + + printf("\n"); + } +} + + +int test_cluster_update_route(redisClusterContext *cc) +{ + int ret; + + ret = cluster_update_route(cc); + + //print_cluster_node_list(cc); + + return ret; +} + +static redisClusterContext *redisClusterContextInit(void) { + redisClusterContext *cc; + + cc = calloc(1,sizeof(redisClusterContext)); + if (cc == NULL) + return NULL; + + cc->err = 0; + cc->errstr[0] = '\0'; + cc->ip = NULL; + cc->port = 0; + cc->flags = 0; + cc->timeout = NULL; + cc->nodes = NULL; + cc->slots = NULL; + cc->max_redirect_count = CLUSTER_DEFAULT_MAX_REDIRECT_COUNT; + cc->retry_count = 0; + cc->requests = NULL; + cc->need_update_route = 0; + cc->update_route_time = 0LL; + + cc->route_version = 0LL; + + memset(cc->table, 0, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); + + return cc; +} + +void redisClusterFree(redisClusterContext *cc) { + + if (cc == NULL) + return; + + if(cc->ip) + { + sdsfree(cc->ip); + cc->ip = NULL; + } + + if (cc->timeout) + { + free(cc->timeout); + } + + memset(cc->table, 0, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); + + if(cc->slots != NULL) + { + cc->slots->nelem = 0; + hiarray_destroy(cc->slots); + cc->slots = NULL; + } + + if(cc->nodes != NULL) + { + dictRelease(cc->nodes); + } + + if(cc->requests != NULL) + { + listRelease(cc->requests); + } + + free(cc); +} + +static int redisClusterAddNode(redisClusterContext *cc, const char *addr) +{ + dictEntry *node_entry; + cluster_node *node; + sds *ip_port = NULL; + int ip_port_count = 0; + sds ip; + int port; + + if(cc == NULL) + { + return REDIS_ERR; + } + + if(cc->nodes == NULL) + { + cc->nodes = dictCreate(&clusterNodesDictType, NULL); + if(cc->nodes == NULL) + { + return REDIS_ERR; + } + } + + node_entry = dictFind(cc->nodes, addr); + if(node_entry == NULL) + { + ip_port = sdssplitlen(addr, strlen(addr), + IP_PORT_SEPARATOR, strlen(IP_PORT_SEPARATOR), &ip_port_count); + if(ip_port == NULL || ip_port_count != 2 || + sdslen(ip_port[0]) <= 0 || sdslen(ip_port[1]) <= 0) + { + if(ip_port != NULL) + { + sdsfreesplitres(ip_port, ip_port_count); + } + __redisClusterSetError(cc,REDIS_ERR_OTHER,"server address is error(correct is like: 127.0.0.1:1234)"); + return REDIS_ERR; + } + + ip = ip_port[0]; + port = hi_atoi(ip_port[1], sdslen(ip_port[1])); + + if(port <= 0) + { + sdsfreesplitres(ip_port, ip_port_count); + __redisClusterSetError(cc,REDIS_ERR_OTHER,"server port is error"); + return REDIS_ERR; + } + + sdsfree(ip_port[1]); + free(ip_port); + ip_port = NULL; + + node = hi_alloc(sizeof(cluster_node)); + if(node == NULL) + { + sdsfree(ip); + __redisClusterSetError(cc,REDIS_ERR_OTHER,"alloc cluster node error"); + return REDIS_ERR; + } + + cluster_node_init(node); + + node->addr = sdsnew(addr); + if(node->addr == NULL) + { + sdsfree(ip); + hi_free(node); + __redisClusterSetError(cc,REDIS_ERR_OTHER,"new node address error"); + return REDIS_ERR; + } + + node->host = ip; + node->port = port; + + dictAdd(cc->nodes, sdsnewlen(node->addr, sdslen(node->addr)), node); + } + + return REDIS_OK; +} + + +/* Connect to a Redis cluster. On error the field error in the returned + * context will be set to the return value of the error function. + * When no set of reply functions is given, the default set will be used. */ +static redisClusterContext *_redisClusterConnect(redisClusterContext *cc, const char *addrs) { + + int ret; + sds *address = NULL; + int address_count = 0; + int i; + + if(cc == NULL) + { + return NULL; + } + + + address = sdssplitlen(addrs, strlen(addrs), CLUSTER_ADDRESS_SEPARATOR, + strlen(CLUSTER_ADDRESS_SEPARATOR), &address_count); + if(address == NULL || address_count <= 0) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"servers address is error(correct is like: 127.0.0.1:1234,127.0.0.2:5678)"); + return cc; + } + + for(i = 0; i < address_count; i ++) + { + ret = redisClusterAddNode(cc, address[i]); + if(ret != REDIS_OK) + { + sdsfreesplitres(address, address_count); + return cc; + } + } + + sdsfreesplitres(address, address_count); + + cluster_update_route(cc); + + return cc; +} + +redisClusterContext *redisClusterConnect(const char *addrs, int flags) +{ + redisClusterContext *cc; + + cc = redisClusterContextInit(); + + if(cc == NULL) + { + return NULL; + } + + cc->flags |= REDIS_BLOCK; + if(flags) + { + cc->flags |= flags; + } + + return _redisClusterConnect(cc, addrs); +} + +redisClusterContext *redisClusterConnectWithTimeout( + const char *addrs, const struct timeval tv, int flags) +{ + redisClusterContext *cc; + + cc = redisClusterContextInit(); + + if(cc == NULL) + { + return NULL; + } + + cc->flags |= REDIS_BLOCK; + if(flags) + { + cc->flags |= flags; + } + + if (cc->timeout == NULL) + { + cc->timeout = malloc(sizeof(struct timeval)); + } + + memcpy(cc->timeout, &tv, sizeof(struct timeval)); + + return _redisClusterConnect(cc, addrs); +} + +redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags) { + + redisClusterContext *cc; + + cc = redisClusterContextInit(); + + if(cc == NULL) + { + return NULL; + } + + cc->flags &= ~REDIS_BLOCK; + if(flags) + { + cc->flags |= flags; + } + + return _redisClusterConnect(cc, addrs); +} + +redisContext *ctx_get_by_node(cluster_node *node, + const struct timeval *timeout, int flags) +{ + redisContext *c = NULL; + if(node == NULL) + { + return NULL; + } + + c = node->con; + if(c != NULL) + { + if(c->err) + { + redisReconnect(c); + } + + return c; + } + + if(node->host == NULL || node->port <= 0) + { + return NULL; + } + + if(flags & REDIS_BLOCK) + { + if(timeout) + { + c = redisConnectWithTimeout(node->host, node->port, *timeout); + } + else + { + c = redisConnect(node->host, node->port); + } + } + else + { + c = redisConnectNonBlock(node->host, node->port); + } + + node->con = c; + + return c; +} + +static cluster_node *node_get_by_slot(redisClusterContext *cc, uint32_t slot_num) +{ + struct hiarray *slots; + uint32_t slot_count; + cluster_slot **slot; + uint32_t middle, start, end; + uint8_t stop = 0; + + if(cc == NULL) + { + return NULL; + } + + if(slot_num >= REDIS_CLUSTER_SLOTS) + { + return NULL; + } + + slots = cc->slots; + if(slots == NULL) + { + return NULL; + } + slot_count = hiarray_n(slots); + + start = 0; + end = slot_count - 1; + middle = 0; + + do{ + if(start >= end) + { + stop = 1; + middle = end; + } + else + { + middle = start + (end - start)/2; + } + + ASSERT(middle < slot_count); + + slot = hiarray_get(slots, middle); + if((*slot)->start > slot_num) + { + end = middle - 1; + } + else if((*slot)->end < slot_num) + { + start = middle + 1; + } + else + { + return (*slot)->node; + } + + + }while(!stop); + + printf("slot_num : %d\n", slot_num); + printf("slot_count : %d\n", slot_count); + printf("start : %d\n", start); + printf("end : %d\n", end); + printf("middle : %d\n", middle); + + return NULL; +} + + +static cluster_node *node_get_by_table(redisClusterContext *cc, uint32_t slot_num) +{ + if(cc == NULL) + { + return NULL; + } + + if(slot_num >= REDIS_CLUSTER_SLOTS) + { + return NULL; + } + + return cc->table[slot_num]; + +} + +static cluster_node *node_get_witch_connected(redisClusterContext *cc) +{ + dictIterator *di; + dictEntry *de; + struct cluster_node *node; + redisContext *c = NULL; + redisReply *reply = NULL; + + if(cc == NULL || cc->nodes == NULL) + { + return NULL; + } + + di = dictGetIterator(cc->nodes); + while((de = dictNext(di)) != NULL) + { + node = dictGetEntryVal(de); + if(node == NULL) + { + continue; + } + + c = ctx_get_by_node(node, cc->timeout, REDIS_BLOCK); + if(c == NULL || c->err) + { + continue; + } + + reply = redisCommand(c, REDIS_COMMAND_PING); + if(reply != NULL && reply->type == REDIS_REPLY_STATUS && + reply->str != NULL && strcmp(reply->str, "PONG") == 0) + { + freeReplyObject(reply); + reply = NULL; + + dictReleaseIterator(di); + + return node; + } + else if(reply != NULL) + { + freeReplyObject(reply); + reply = NULL; + } + } + + dictReleaseIterator(di); + + return NULL; +} + +static int slot_get_by_command(redisClusterContext *cc, char *cmd, int len) +{ + struct cmd *command = NULL; + struct keypos *kp; + int key_count; + uint32_t i; + int slot_num = -1; + + if(cc == NULL || cmd == NULL || len <= 0) + { + goto done; + } + + command = command_get(); + if(command == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto done; + } + + command->cmd = cmd; + command->clen = len; + redis_parse_cmd(command); + if(command->result != CMD_PARSE_OK) + { + __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, "parse command error"); + goto done; + } + + key_count = hiarray_n(command->keys); + + if(key_count <= 0) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "no keys in command(must have keys for redis cluster mode)"); + goto done; + } + else if(key_count == 1) + { + kp = hiarray_get(command->keys, 0); + slot_num = keyHashSlot(kp->start, kp->end - kp->start); + + goto done; + } + + for(i = 0; i < hiarray_n(command->keys); i ++) + { + kp = hiarray_get(command->keys, i); + + slot_num = keyHashSlot(kp->start, kp->end - kp->start); + } + +done: + + if(command != NULL) + { + command->cmd = NULL; + command_destroy(command); + } + + return slot_num; +} + +/* Get the cluster config from one node. + * Return value: config_value string must free by usr. + */ +static char * cluster_config_get(redisClusterContext *cc, + const char *config_name, int *config_value_len) +{ + redisContext *c; + cluster_node *node; + redisReply *reply = NULL, *sub_reply; + char *config_value = NULL; + + if(cc == NULL || config_name == NULL + || config_value_len == NULL) + { + return NULL; + } + + node = node_get_witch_connected(cc); + if(node == NULL) + { + __redisClusterSetError(cc, + REDIS_ERR_OTHER, "no reachable node in cluster"); + goto error; + } + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + + reply = redisCommand(c, "config get %s", config_name); + if(reply == NULL) + { + __redisClusterSetError(cc, + REDIS_ERR_OTHER, "reply for config get is null"); + goto error; + } + + if(reply->type != REDIS_REPLY_ARRAY) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "reply for config get type is not array"); + goto error; + } + + if(reply->elements != 2) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "reply for config get elements number is not 2"); + goto error; + } + + sub_reply = reply->element[0]; + if(sub_reply == NULL || sub_reply->type != REDIS_REPLY_STRING) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "reply for config get config name is not string"); + goto error; + } + + if(strcmp(sub_reply->str, config_name)) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "reply for config get config name is not we want"); + goto error; + } + + sub_reply = reply->element[1]; + if(sub_reply == NULL || sub_reply->type != REDIS_REPLY_STRING) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "reply for config get config value type is not string"); + goto error; + } + + config_value = sub_reply->str; + *config_value_len = sub_reply->len; + sub_reply->str= NULL; + + if(reply != NULL) + { + freeReplyObject(reply); + } + + return config_value; + +error: + + if(reply != NULL) + { + freeReplyObject(reply); + } + + return NULL; +} + +/* Helper function for the redisClusterAppendCommand* family of functions. + * + * Write a formatted command to the output buffer. When this family + * is used, you need to call redisGetReply yourself to retrieve + * the reply (or replies in pub/sub). + */ +static int __redisClusterAppendCommand(redisClusterContext *cc, + struct cmd *command) { + + cluster_node *node; + redisContext *c = NULL; + + if(cc == NULL || command == NULL) + { + return REDIS_ERR; + } + + node = node_get_by_table(cc, (uint32_t)command->slot_num); + if(node == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "node get by slot error"); + return REDIS_ERR; + } + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + if(c == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node is null"); + return REDIS_ERR; + } + else if(c->err) + { + __redisClusterSetError(cc, c->err, c->errstr); + return REDIS_ERR; + } + + if (__redisAppendCommand(c, command->cmd, command->clen) != REDIS_OK) + { + __redisClusterSetError(cc, c->err, c->errstr); + return REDIS_ERR; + } + + return REDIS_OK; +} + +/* Helper function for the redisClusterGetReply* family of functions. + */ +static int __redisClusterGetReply(redisClusterContext *cc, int slot_num, void **reply) +{ + cluster_node *node; + redisContext *c; + + if(cc == NULL || slot_num < 0 || reply == NULL) + { + return REDIS_ERR; + } + + node = node_get_by_table(cc, (uint32_t)slot_num); + if(node == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "node get by table is null"); + return REDIS_ERR; + } + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + if(c == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + else if(c->err) + { + if(cc->need_update_route == 0) + { + cc->retry_count ++; + if(cc->retry_count > cc->max_redirect_count) + { + cc->need_update_route = 1; + cc->retry_count = 0; + } + } + __redisClusterSetError(cc, c->err, c->errstr); + return REDIS_ERR; + } + + if(redisGetReply(c, reply) != REDIS_OK) + { + __redisClusterSetError(cc, c->err, c->errstr); + return REDIS_ERR; + } + + if(cluster_reply_error_type(*reply) == CLUSTER_ERR_MOVED) + { + cc->need_update_route = 1; + } + + return REDIS_OK; +} + +static cluster_node *node_get_by_ask_error_reply( + redisClusterContext *cc, redisReply *reply) +{ + sds *part = NULL, *ip_port = NULL; + int part_len = 0, ip_port_len; + dictEntry *de; + cluster_node *node = NULL; + + if(cc == NULL || reply == NULL) + { + return NULL; + } + + if(cluster_reply_error_type(reply) != CLUSTER_ERR_ASK) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "reply is not ask error!"); + return NULL; + } + + part = sdssplitlen(reply->str, reply->len, " ", 1, &part_len); + + if(part != NULL && part_len == 3) + { + ip_port = sdssplitlen(part[2], sdslen(part[2]), + ":", 1, &ip_port_len); + + if(ip_port != NULL && ip_port_len == 2) + { + de = dictFind(cc->nodes, part[2]); + if(de == NULL) + { + node = hi_alloc(sizeof(cluster_node)); + if(node == NULL) + { + __redisClusterSetError(cc, + REDIS_ERR_OOM, "Out of memory"); + + goto done; + } + + cluster_node_init(node); + node->addr = part[1]; + node->host = ip_port[0]; + node->port = hi_atoi(ip_port[1], sdslen(ip_port[1])); + node->role = REDIS_ROLE_MASTER; + + dictAdd(cc->nodes, sdsnewlen(node->addr, sdslen(node->addr)), node); + + part = NULL; + ip_port = NULL; + } + else + { + node = de->val; + + goto done; + } + } + else + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "ask error reply address part parse error!"); + + goto done; + } + + } + else + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "ask error reply parse error!"); + + goto done; + } + +done: + + if(part != NULL) + { + sdsfreesplitres(part, part_len); + part = NULL; + } + + if(ip_port != NULL) + { + sdsfreesplitres(ip_port, ip_port_len); + ip_port = NULL; + } + + return node; +} + +static void *redis_cluster_command_execute(redisClusterContext *cc, + struct cmd *command) +{ + int ret; + void *reply = NULL; + cluster_node *node; + redisContext *c = NULL; + int error_type; + +retry: + + node = node_get_by_table(cc, (uint32_t)command->slot_num); + if(node == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "node get by table error"); + return NULL; + } + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + if(c == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node is null"); + return NULL; + } + else if(c->err) + { + node = node_get_witch_connected(cc); + if(node == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "no reachable node in cluster"); + return NULL; + } + + cc->retry_count ++; + if(cc->retry_count > cc->max_redirect_count) + { + __redisClusterSetError(cc, REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT, + "too many cluster redirect"); + return NULL; + } + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + if(c == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node error"); + return NULL; + } + else if(c->err) + { + __redisClusterSetError(cc, c->err, c->errstr); + return NULL; + } + } + +ask_retry: + + if (__redisAppendCommand(c,command->cmd, command->clen) != REDIS_OK) + { + __redisClusterSetError(cc, c->err, c->errstr); + return NULL; + } + + reply = __redisBlockForReply(c); + if(reply == NULL) + { + __redisClusterSetError(cc, c->err, c->errstr); + return NULL; + } + + error_type = cluster_reply_error_type(reply); + if(error_type > CLUSTER_NOT_ERR && error_type < CLUSTER_ERR_SENTINEL) + { + cc->retry_count ++; + if(cc->retry_count > cc->max_redirect_count) + { + __redisClusterSetError(cc, REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT, + "too many cluster redirect"); + freeReplyObject(reply); + return NULL; + } + + switch(error_type) + { + case CLUSTER_ERR_MOVED: + freeReplyObject(reply); + reply = NULL; + ret = cluster_update_route(cc); + if(ret != REDIS_OK) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "route update error, please recreate redisClusterContext!"); + return NULL; + } + + goto retry; + + break; + case CLUSTER_ERR_ASK: + node = node_get_by_ask_error_reply(cc, reply); + if(node == NULL) + { + freeReplyObject(reply); + return NULL; + } + + freeReplyObject(reply); + reply = NULL; + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + if(c == NULL) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node error"); + return NULL; + } + else if(c->err) + { + __redisClusterSetError(cc, c->err, c->errstr); + return NULL; + } + + reply = redisCommand(c, REDIS_COMMAND_ASKING); + if(reply == NULL) + { + __redisClusterSetError(cc, c->err, c->errstr); + return NULL; + } + + freeReplyObject(reply); + reply = NULL; + + goto ask_retry; + + break; + case CLUSTER_ERR_TRYAGAIN: + case CLUSTER_ERR_CROSSSLOT: + case CLUSTER_ERR_CLUSTERDOWN: + freeReplyObject(reply); + reply = NULL; + goto retry; + + break; + default: + + break; + } + } + + return reply; +} + +static int command_pre_fragment(redisClusterContext *cc, + struct cmd *command, hilist *commands) +{ + + struct keypos *kp, *sub_kp; + uint32_t key_count; + uint32_t i, j; + uint32_t idx; + uint32_t key_len; + int slot_num = -1; + struct cmd *sub_command; + struct cmd **sub_commands = NULL; + char num_str[12]; + uint8_t num_str_len; + + + if(command == NULL || commands == NULL) + { + goto done; + } + + key_count = hiarray_n(command->keys); + + sub_commands = hi_zalloc(REDIS_CLUSTER_SLOTS * sizeof(*sub_commands)); + if (sub_commands == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto done; + } + + command->frag_seq = hi_alloc(key_count * sizeof(*command->frag_seq)); + if(command->frag_seq == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto done; + } + + + for(i = 0; i < key_count; i ++) + { + kp = hiarray_get(command->keys, i); + + slot_num = keyHashSlot(kp->start, kp->end - kp->start); + + if(slot_num < 0 || slot_num >= REDIS_CLUSTER_SLOTS) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"keyHashSlot return error"); + goto done; + } + + if (sub_commands[slot_num] == NULL) { + sub_commands[slot_num] = command_get(); + if (sub_commands[slot_num] == NULL) { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + slot_num = -1; + goto done; + } + } + + command->frag_seq[i] = sub_command = sub_commands[slot_num]; + + sub_command->narg++; + + sub_kp = hiarray_push(sub_command->keys); + if (sub_kp == NULL) { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + slot_num = -1; + goto done; + } + + sub_kp->start = kp->start; + sub_kp->end = kp->end; + + key_len = (uint32_t)(kp->end - kp->start); + + sub_command->clen += key_len + uint_len(key_len); + + sub_command->slot_num = slot_num; + + if (command->type == CMD_REQ_REDIS_MSET) { + uint32_t len = 0; + char *p; + + for (p = sub_kp->end + 1; !isdigit(*p); p++){} + + p = sub_kp->end + 1; + while(!isdigit(*p)) + { + p ++; + } + + for (; isdigit(*p); p++) { + len = len * 10 + (uint32_t)(*p - '0'); + } + + len += CRLF_LEN * 2; + len += (p - sub_kp->end); + sub_kp->remain_len = len; + sub_command->clen += len; + } + } + + for (i = 0; i < REDIS_CLUSTER_SLOTS; i++) { /* prepend command header */ + sub_command = sub_commands[i]; + if (sub_command == NULL) { + continue; + } + + idx = 0; + if (command->type == CMD_REQ_REDIS_MGET) { + //"*%d\r\n$4\r\nmget\r\n" + + sub_command->clen += 5*sub_command->narg; + + sub_command->narg ++; + + hi_itoa(num_str, sub_command->narg); + num_str_len = (uint8_t)(strlen(num_str)); + + sub_command->clen += 13 + num_str_len; + + sub_command->cmd = hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + if(sub_command->cmd == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + slot_num = -1; + goto done; + } + + sub_command->cmd[idx++] = '*'; + memcpy(sub_command->cmd + idx, num_str, num_str_len); + idx += num_str_len; + memcpy(sub_command->cmd + idx, "\r\n$4\r\nmget\r\n", 12); + idx += 12; + + for(j = 0; j < hiarray_n(sub_command->keys); j ++) + { + kp = hiarray_get(sub_command->keys, j); + key_len = (uint32_t)(kp->end - kp->start); + hi_itoa(num_str, key_len); + num_str_len = strlen(num_str); + + sub_command->cmd[idx++] = '$'; + memcpy(sub_command->cmd + idx, num_str, num_str_len); + idx += num_str_len; + memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); + idx += CRLF_LEN; + memcpy(sub_command->cmd + idx, kp->start, key_len); + idx += key_len; + memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); + idx += CRLF_LEN; + } + } else if (command->type == CMD_REQ_REDIS_DEL) { + //"*%d\r\n$3\r\ndel\r\n" + + sub_command->clen += 5*sub_command->narg; + + sub_command->narg ++; + + hi_itoa(num_str, sub_command->narg); + num_str_len = (uint8_t)strlen(num_str); + + sub_command->clen += 12 + num_str_len; + + sub_command->cmd = hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + if(sub_command->cmd == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + slot_num = -1; + goto done; + } + + sub_command->cmd[idx++] = '*'; + memcpy(sub_command->cmd + idx, num_str, num_str_len); + idx += num_str_len; + memcpy(sub_command->cmd + idx, "\r\n$3\r\ndel\r\n", 11); + idx += 11; + + for(j = 0; j < hiarray_n(sub_command->keys); j ++) + { + kp = hiarray_get(sub_command->keys, j); + key_len = (uint32_t)(kp->end - kp->start); + hi_itoa(num_str, key_len); + num_str_len = strlen(num_str); + + sub_command->cmd[idx++] = '$'; + memcpy(sub_command->cmd + idx, num_str, num_str_len); + idx += num_str_len; + memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); + idx += CRLF_LEN; + memcpy(sub_command->cmd + idx, kp->start, key_len); + idx += key_len; + memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); + idx += CRLF_LEN; + } + } else if (command->type == CMD_REQ_REDIS_MSET) { + //"*%d\r\n$4\r\nmset\r\n" + + sub_command->clen += 3*sub_command->narg; + + sub_command->narg *= 2; + + sub_command->narg ++; + + hi_itoa(num_str, sub_command->narg); + num_str_len = (uint8_t)strlen(num_str); + + sub_command->clen += 13 + num_str_len; + + sub_command->cmd = hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); + if(sub_command->cmd == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + slot_num = -1; + goto done; + } + + sub_command->cmd[idx++] = '*'; + memcpy(sub_command->cmd + idx, num_str, num_str_len); + idx += num_str_len; + memcpy(sub_command->cmd + idx, "\r\n$4\r\nmset\r\n", 12); + idx += 12; + + for(j = 0; j < hiarray_n(sub_command->keys); j ++) + { + kp = hiarray_get(sub_command->keys, j); + key_len = (uint32_t)(kp->end - kp->start); + hi_itoa(num_str, key_len); + num_str_len = strlen(num_str); + + sub_command->cmd[idx++] = '$'; + memcpy(sub_command->cmd + idx, num_str, num_str_len); + idx += num_str_len; + memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); + idx += CRLF_LEN; + memcpy(sub_command->cmd + idx, kp->start, key_len + kp->remain_len); + idx += key_len + kp->remain_len; + + } + } else { + NOT_REACHED(); + } + + //printf("len : %d\n", sub_command->clen); + //print_string_with_length_fix_CRLF(sub_command->cmd, sub_command->clen); + + sub_command->type = command->type; + + listAddNodeTail(commands, sub_command); + } + +done: + + if(sub_commands != NULL) + { + hi_free(sub_commands); + } + + if(slot_num >= 0 && commands != NULL + && listLength(commands) == 1) + { + listNode *list_node = listFirst(commands); + listDelNode(commands, list_node); + if(command->frag_seq) + { + hi_free(command->frag_seq); + command->frag_seq = NULL; + } + + command->slot_num = slot_num; + } + + return slot_num; +} + +static void *command_post_fragment(redisClusterContext *cc, + struct cmd *command, hilist *commands) +{ + struct cmd *sub_command; + listNode *list_node; + listIter *list_iter; + redisReply *reply, *sub_reply; + long long count = 0; + + list_iter = listGetIterator(commands, AL_START_HEAD); + while((list_node = listNext(list_iter)) != NULL) + { + sub_command = list_node->value; + reply = sub_command->reply; + if(reply == NULL) + { + return NULL; + } + else if(reply->type == REDIS_REPLY_ERROR) + { + return reply; + } + + if (command->type == CMD_REQ_REDIS_MGET) { + if(reply->type != REDIS_REPLY_ARRAY) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"reply type is error(here only can be array)"); + return NULL; + } + }else if(command->type == CMD_REQ_REDIS_DEL){ + if(reply->type != REDIS_REPLY_INTEGER) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"reply type is error(here only can be integer)"); + return NULL; + } + + count += reply->integer; + }else if(command->type == CMD_REQ_REDIS_MSET){ + if(reply->type != REDIS_REPLY_STATUS || + reply->len != 2 || strcmp(reply->str, REDIS_STATUS_OK) != 0) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"reply type is error(here only can be status and ok)"); + return NULL; + } + }else { + NOT_REACHED(); + } + } + + reply = hi_calloc(1,sizeof(*reply)); + + if (reply == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return NULL; + } + + if (command->type == CMD_REQ_REDIS_MGET) { + int i; + uint32_t key_count; + + reply->type = REDIS_REPLY_ARRAY; + + key_count = hiarray_n(command->keys); + + reply->elements = key_count; + reply->element = hi_calloc(key_count, sizeof(*reply)); + if (reply->element == NULL) { + freeReplyObject(reply); + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return NULL; + } + + for (i = key_count - 1; i >= 0; i--) { /* for each key */ + sub_reply = command->frag_seq[i]->reply; /* get it's reply */ + if (sub_reply == NULL) { + freeReplyObject(reply); + __redisClusterSetError(cc,REDIS_ERR_OTHER,"sub reply is null"); + return NULL; + } + + if(sub_reply->type == REDIS_REPLY_STRING) + { + reply->element[i] = sub_reply; + } + else if(sub_reply->type == REDIS_REPLY_ARRAY) + { + if(sub_reply->elements == 0) + { + freeReplyObject(reply); + __redisClusterSetError(cc,REDIS_ERR_OTHER,"sub reply elements error"); + return NULL; + } + + reply->element[i] = sub_reply->element[sub_reply->elements - 1]; + sub_reply->elements --; + } + } + }else if(command->type == CMD_REQ_REDIS_DEL){ + reply->type = REDIS_REPLY_INTEGER; + reply->integer = count; + }else if(command->type == CMD_REQ_REDIS_MSET){ + reply->type = REDIS_REPLY_STATUS; + uint32_t str_len = strlen(REDIS_STATUS_OK); + reply->str = hi_alloc((str_len + 1) * sizeof(char*)); + if(reply->str == NULL) + { + freeReplyObject(reply); + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return NULL; + } + + reply->len = str_len; + memcpy(reply->str, REDIS_STATUS_OK, str_len); + reply->str[str_len] = '\0'; + }else { + NOT_REACHED(); + } + + return reply; +} + +/* + * Split the command into subcommands by slot + * + * Returns slot_num + * If slot_num < 0 or slot_num >= REDIS_CLUSTER_SLOTS means this function runs error; + * Otherwise if the commands > 1 , slot_num is the last subcommand slot number. + */ +static int command_format_by_slot(redisClusterContext *cc, + struct cmd *command, hilist *commands) +{ + struct keypos *kp; + int key_count; + int slot_num = -1; + + if(cc == NULL || commands == NULL || + command == NULL || + command->cmd == NULL || command->clen <= 0) + { + goto done; + } + + + redis_parse_cmd(command); + if(command->result == CMD_PARSE_ENOMEM) + { + __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, "Parse command error: out of memory"); + goto done; + } + else if(command->result != CMD_PARSE_OK) + { + __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, command->errstr); + goto done; + } + + key_count = hiarray_n(command->keys); + + if(key_count <= 0) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, "No keys in command(must have keys for redis cluster mode)"); + goto done; + } + else if(key_count == 1) + { + kp = hiarray_get(command->keys, 0); + slot_num = keyHashSlot(kp->start, kp->end - kp->start); + command->slot_num = slot_num; + + goto done; + } + + slot_num = command_pre_fragment(cc, command, commands); + +done: + + return slot_num; +} + + +void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count) +{ + if(cc == NULL || max_redirect_count <= 0) + { + return; + } + + cc->max_redirect_count = max_redirect_count; +} + +void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len) { + redisReply *reply = NULL; + int slot_num; + struct cmd *command = NULL, *sub_command; + hilist *commands = NULL; + listNode *list_node; + listIter *list_iter = NULL; + + if(cc == NULL) + { + return NULL; + } + + if(cc->err) + { + cc->err = 0; + memset(cc->errstr, '\0', strlen(cc->errstr)); + } + + command = command_get(); + if(command == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return NULL; + } + + command->cmd = cmd; + command->clen = len; + + commands = listCreate(); + if(commands == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + commands->free = listCommandFree; + + slot_num = command_format_by_slot(cc, command, commands); + + if(slot_num < 0) + { + goto error; + } + else if(slot_num >= REDIS_CLUSTER_SLOTS) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"slot_num is out of range"); + goto error; + } + + //all keys belong to one slot + if(listLength(commands) == 0) + { + reply = redis_cluster_command_execute(cc, command); + goto done; + } + + ASSERT(listLength(commands) != 1); + + list_iter = listGetIterator(commands, AL_START_HEAD); + while((list_node = listNext(list_iter)) != NULL) + { + sub_command = list_node->value; + + reply = redis_cluster_command_execute(cc, sub_command); + if(reply == NULL) + { + goto error; + } + else if(reply->type == REDIS_REPLY_ERROR) + { + goto done; + } + + sub_command->reply = reply; + } + + reply = command_post_fragment(cc, command, commands); + +done: + + command->cmd = NULL; + command_destroy(command); + + if(commands != NULL) + { + listRelease(commands); + } + + if(list_iter != NULL) + { + listReleaseIterator(list_iter); + } + + cc->retry_count = 0; + + return reply; + +error: + + if(command != NULL) + { + command->cmd = NULL; + command_destroy(command); + } + + if(commands != NULL) + { + listRelease(commands); + } + + if(list_iter != NULL) + { + listReleaseIterator(list_iter); + } + + cc->retry_count = 0; + + return NULL; +} + +void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap) { + redisReply *reply; + char *cmd; + int len; + + if(cc == NULL) + { + return NULL; + } + + len = redisvFormatCommand(&cmd,format,ap); + + if (len == -1) { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return NULL; + } else if (len == -2) { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"Invalid format string"); + return NULL; + } + + reply = redisClusterFormattedCommand(cc, cmd, len); + + free(cmd); + + return reply; +} + +void *redisClusterCommand(redisClusterContext *cc, const char *format, ...) { + va_list ap; + redisReply *reply = NULL; + + va_start(ap,format); + reply = redisClustervCommand(cc, format, ap); + va_end(ap); + + return reply; +} + +void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen) { + redisReply *reply = NULL; + char *cmd; + int len; + + len = redisFormatCommandArgv(&cmd,argc,argv,argvlen); + if (len == -1) { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return NULL; + } + + reply = redisClusterFormattedCommand(cc, cmd, len); + + free(cmd); + + return reply; +} + +int redisClusterAppendFormattedCommand(redisClusterContext *cc, + char *cmd, int len) { + int slot_num; + struct cmd *command = NULL, *sub_command; + hilist *commands = NULL; + listNode *list_node; + listIter *list_iter = NULL; + + if(cc->requests == NULL) + { + cc->requests = listCreate(); + if(cc->requests == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + cc->requests->free = listCommandFree; + } + + command = command_get(); + if(command == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + command->cmd = cmd; + command->clen = len; + + commands = listCreate(); + if(commands == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + commands->free = listCommandFree; + + slot_num = command_format_by_slot(cc, command, commands); + + if(slot_num < 0) + { + goto error; + } + else if(slot_num >= REDIS_CLUSTER_SLOTS) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"slot_num is out of range"); + goto error; + } + + //all keys belong to one slot + if(listLength(commands) == 0) + { + if(__redisClusterAppendCommand(cc, command) == REDIS_OK) + { + goto done; + } + else + { + goto error; + } + } + + ASSERT(listLength(commands) != 1); + + list_iter = listGetIterator(commands, AL_START_HEAD); + while((list_node = listNext(list_iter)) != NULL) + { + sub_command = list_node->value; + + if(__redisClusterAppendCommand(cc, sub_command) == REDIS_OK) + { + continue; + } + else + { + goto error; + } + } + +done: + + if(command->cmd != NULL) + { + command->cmd = NULL; + } + else + { + goto error; + } + + if(commands != NULL) + { + if(listLength(commands) > 0) + { + command->sub_commands = commands; + } + else + { + listRelease(commands); + } + } + + if(list_iter != NULL) + { + listReleaseIterator(list_iter); + } + + listAddNodeTail(cc->requests, command); + + return REDIS_OK; + +error: + + if(command != NULL) + { + command->cmd = NULL; + command_destroy(command); + } + + if(commands != NULL) + { + listRelease(commands); + } + + if(list_iter != NULL) + { + listReleaseIterator(list_iter); + } + + /* Attention: mybe here we must pop the + sub_commands that had append to the nodes. + But now we do not handle it. */ + + return REDIS_ERR; +} + + +int redisClustervAppendCommand(redisClusterContext *cc, + const char *format, va_list ap) { + int ret; + char *cmd; + int len; + + len = redisvFormatCommand(&cmd,format,ap); + if (len == -1) { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } else if (len == -2) { + __redisClusterSetError(cc,REDIS_ERR_OTHER,"Invalid format string"); + return REDIS_ERR; + } + + ret = redisClusterAppendFormattedCommand(cc, cmd, len); + + free(cmd); + + return ret; +} + +int redisClusterAppendCommand(redisClusterContext *cc, + const char *format, ...) { + + int ret; + va_list ap; + + if(cc == NULL || format == NULL) + { + return REDIS_ERR; + } + + va_start(ap,format); + ret = redisClustervAppendCommand(cc, format, ap); + va_end(ap); + + return ret; +} + +int redisClusterAppendCommandArgv(redisClusterContext *cc, + int argc, const char **argv, const size_t *argvlen) { + int ret; + char *cmd; + int len; + + len = redisFormatCommandArgv(&cmd,argc,argv,argvlen); + if (len == -1) { + __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + ret = redisClusterAppendFormattedCommand(cc, cmd, len); + + free(cmd); + + return ret; +} + +static int redisCLusterSendAll(redisClusterContext *cc) +{ + dictIterator *di; + dictEntry *de; + struct cluster_node *node; + redisContext *c = NULL; + int wdone = 0; + + if(cc == NULL || cc->nodes == NULL) + { + return REDIS_ERR; + } + + di = dictGetIterator(cc->nodes); + while((de = dictNext(di)) != NULL) + { + node = dictGetEntryVal(de); + if(node == NULL) + { + continue; + } + + c = ctx_get_by_node(node, cc->timeout, cc->flags); + if(c == NULL) + { + continue; + } + + if (c->flags & REDIS_BLOCK) { + /* Write until done */ + do { + if (redisBufferWrite(c,&wdone) == REDIS_ERR) + { + dictReleaseIterator(di); + return REDIS_ERR; + } + } while (!wdone); + } + } + + dictReleaseIterator(di); + + return REDIS_OK; +} + +static int redisCLusterClearAll(redisClusterContext *cc) +{ + dictIterator *di; + dictEntry *de; + struct cluster_node *node; + redisContext *c = NULL; + + if (cc == NULL) { + return REDIS_ERR; + } + + if (cc->err) { + cc->err = 0; + memset(cc->errstr, '\0', strlen(cc->errstr)); + } + + if (cc->nodes == NULL) { + return REDIS_ERR; + } + di = dictGetIterator(cc->nodes); + while((de = dictNext(di)) != NULL) + { + node = dictGetEntryVal(de); + if(node == NULL) + { + continue; + } + + c = node->con; + if(c == NULL) + { + continue; + } + + redisFree(c); + node->con = NULL; + } + + dictReleaseIterator(di); + + return REDIS_OK; +} + +int redisClusterGetReply(redisClusterContext *cc, void **reply) { + + struct cmd *command, *sub_command; + hilist *commands = NULL; + listNode *list_command, *list_sub_command; + listIter *list_iter; + int slot_num; + void *sub_reply; + + if(cc == NULL || reply == NULL) + return REDIS_ERR; + + cc->err = 0; + cc->errstr[0] = '\0'; + + *reply = NULL; + + if (cc->requests == NULL) + return REDIS_ERR; + + list_command = listFirst(cc->requests); + + //no more reply + if(list_command == NULL) + { + *reply = NULL; + return REDIS_OK; + } + + command = list_command->value; + if(command == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "command in the requests list is null"); + goto error; + } + + slot_num = command->slot_num; + if(slot_num >= 0) + { + listDelNode(cc->requests, list_command); + return __redisClusterGetReply(cc, slot_num, reply); + } + + commands = command->sub_commands; + if(commands == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "sub_commands in command is null"); + goto error; + } + + ASSERT(listLength(commands) != 1); + + list_iter = listGetIterator(commands, AL_START_HEAD); + while((list_sub_command = listNext(list_iter)) != NULL) + { + sub_command = list_sub_command->value; + if(sub_command == NULL) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "sub_command is null"); + goto error; + } + + slot_num = sub_command->slot_num; + if(slot_num < 0) + { + __redisClusterSetError(cc,REDIS_ERR_OTHER, + "sub_command slot_num is less then zero"); + goto error; + } + + if(__redisClusterGetReply(cc, slot_num, &sub_reply) != REDIS_OK) + { + goto error; + } + + sub_command->reply = sub_reply; + } + + *reply = command_post_fragment(cc, command, commands); + if(*reply == NULL) + { + goto error; + } + + listDelNode(cc->requests, list_command); + return REDIS_OK; + +error: + + listDelNode(cc->requests, list_command); + return REDIS_ERR; +} + +void redisClusterReset(redisClusterContext *cc) +{ + int status; + void *reply; + + if(cc == NULL || cc->nodes == NULL) + { + return; + } + + if (cc->err) { + redisCLusterClearAll(cc); + } else { + redisCLusterSendAll(cc); + + do { + status = redisClusterGetReply(cc, &reply); + if (status == REDIS_OK) { + freeReplyObject(reply); + } else { + redisCLusterClearAll(cc); + break; + } + } while(reply != NULL); + } + + if(cc->requests) + { + listRelease(cc->requests); + cc->requests = NULL; + } + + if(cc->need_update_route) + { + status = cluster_update_route(cc); + if(status != REDIS_OK) + { + __redisClusterSetError(cc, REDIS_ERR_OTHER, + "route update error, please recreate redisClusterContext!"); + return; + } + cc->need_update_route = 0; + } +} + +/*############redis cluster async############*/ + +/* We want the error field to be accessible directly instead of requiring + * an indirection to the redisContext struct. */ +static void __redisClusterAsyncCopyError(redisClusterAsyncContext *acc) { + if (!acc) + return; + + redisClusterContext *cc = acc->cc; + acc->err = cc->err; + memcpy(acc->errstr, cc->errstr, 128); +} + +static void __redisClusterAsyncSetError(redisClusterAsyncContext *acc, + int type, const char *str) { + + size_t len; + + acc->err = type; + if (str != NULL) { + len = strlen(str); + len = len < (sizeof(acc->errstr)-1) ? len : (sizeof(acc->errstr)-1); + memcpy(acc->errstr,str,len); + acc->errstr[len] = '\0'; + } else { + /* Only REDIS_ERR_IO may lack a description! */ + assert(type == REDIS_ERR_IO); + __redis_strerror_r(errno, acc->errstr, sizeof(acc->errstr)); + } +} + +static redisClusterAsyncContext *redisClusterAsyncInitialize(redisClusterContext *cc) { + redisClusterAsyncContext *acc; + + if(cc == NULL) + { + return NULL; + } + + acc = hi_alloc(sizeof(redisClusterAsyncContext)); + if (acc == NULL) + return NULL; + + acc->cc = cc; + + acc->err = 0; + acc->data = NULL; + acc->adapter = NULL; + acc->attach_fn = NULL; + + acc->onConnect = NULL; + acc->onDisconnect = NULL; + + return acc; +} + +static cluster_async_data *cluster_async_data_get(void) +{ + cluster_async_data *cad; + + cad = hi_alloc(sizeof(cluster_async_data)); + if(cad == NULL) + { + return NULL; + } + + cad->acc = NULL; + cad->command = NULL; + cad->callback = NULL; + cad->privdata = NULL; + cad->retry_count = 0; + + return cad; +} + +static void cluster_async_data_free(cluster_async_data *cad) +{ + if(cad == NULL) + { + return; + } + + if(cad->command != NULL) + { + command_destroy(cad->command); + } + + hi_free(cad); + cad = NULL; +} + +static void unlinkAsyncContextAndNode(redisAsyncContext* ac) +{ + cluster_node *node; + + if (ac->data) { + node = (cluster_node *)(ac->data); + node->acon = NULL; + } +} + +redisAsyncContext * actx_get_by_node(redisClusterAsyncContext *acc, + cluster_node *node) +{ + redisAsyncContext *ac; + + if(node == NULL) + { + return NULL; + } + + ac = node->acon; + if(ac != NULL) + { + if (ac->c.err == 0) { + return ac; + } else { + NOT_REACHED(); + } + } + + if(node->host == NULL || node->port <= 0) + { + __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, "node host or port is error"); + return NULL; + } + + ac = redisAsyncConnect(node->host, node->port); + if(ac == NULL) + { + __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, "node host or port is error"); + return NULL; + } + + if(acc->adapter) + { + acc->attach_fn(ac, acc->adapter); + } + + if(acc->onConnect) + { + redisAsyncSetConnectCallback(ac, acc->onConnect); + } + + if(acc->onDisconnect) + { + redisAsyncSetDisconnectCallback(ac, acc->onDisconnect); + } + + ac->data = node; + ac->dataHandler = unlinkAsyncContextAndNode; + node->acon = ac; + + return ac; +} + +static redisAsyncContext *actx_get_after_update_route_by_slot( + redisClusterAsyncContext *acc, int slot_num) +{ + int ret; + redisClusterContext *cc; + redisAsyncContext *ac; + cluster_node *node; + + if(acc == NULL || slot_num < 0) + { + return NULL; + } + + cc = acc->cc; + if(cc == NULL) + { + return NULL; + } + + ret = cluster_update_route(cc); + if(ret != REDIS_OK) + { + __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, + "route update error, please recreate redisClusterContext!"); + return NULL; + } + + node = node_get_by_table(cc, (uint32_t)slot_num); + if(node == NULL) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, "node get by table error"); + return NULL; + } + + ac = actx_get_by_node(acc, node); + if(ac == NULL) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, "actx get by node error"); + return NULL; + } + else if(ac->err) + { + __redisClusterAsyncSetError(acc, ac->err, ac->errstr); + return NULL; + } + + return ac; +} + +redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags) { + + redisClusterContext *cc; + redisClusterAsyncContext *acc; + + cc = redisClusterConnectNonBlock(addrs, flags); + if(cc == NULL) + { + return NULL; + } + + acc = redisClusterAsyncInitialize(cc); + if (acc == NULL) { + redisClusterFree(cc); + return NULL; + } + + __redisClusterAsyncCopyError(acc); + + return acc; +} + + +int redisClusterAsyncSetConnectCallback( + redisClusterAsyncContext *acc, redisConnectCallback *fn) +{ + if (acc->onConnect == NULL) { + acc->onConnect = fn; + return REDIS_OK; + } + return REDIS_ERR; +} + +int redisClusterAsyncSetDisconnectCallback( + redisClusterAsyncContext *acc, redisDisconnectCallback *fn) +{ + if (acc->onDisconnect == NULL) { + acc->onDisconnect = fn; + return REDIS_OK; + } + return REDIS_ERR; +} + +static void redisClusterAsyncCallback(redisAsyncContext *ac, void *r, void *privdata) { + int ret; + redisReply *reply = r; + cluster_async_data *cad = privdata; + redisClusterAsyncContext *acc; + redisClusterContext *cc; + redisAsyncContext *ac_retry = NULL; + int error_type; + cluster_node *node; + struct cmd *command; + int64_t now, next; + + if(cad == NULL) + { + goto error; + } + + acc = cad->acc; + if(acc == NULL) + { + goto error; + } + + cc = acc->cc; + if(cc == NULL) + { + goto error; + } + + command = cad->command; + if(command == NULL) + { + goto error; + } + + if(reply == NULL) + { + //Note: + //I can't decide witch is the best way to deal with connect + //problem for hiredis cluster async api. + //But now the way is : when enough null reply for a node, + //we will update the route after the cluster node timeout. + //If you have a better idea, please contact with me. Thank you. + //My email: diguo58@gmail.com + + node = (cluster_node *)(ac->data); + ASSERT(node != NULL); + + __redisClusterAsyncSetError(acc, + ac->err, ac->errstr); + + if(cc->update_route_time != 0) + { + now = hi_usec_now(); + if(now >= cc->update_route_time) + { + ret = cluster_update_route(cc); + if(ret != REDIS_OK) + { + __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, + "route update error, please recreate redisClusterContext!"); + } + + cc->update_route_time = 0LL; + } + + goto done; + } + + node->failure_count ++; + if(node->failure_count > cc->max_redirect_count) + { + char *cluster_timeout_str; + int cluster_timeout_str_len; + int cluster_timeout; + + node->failure_count = 0; + if(cc->update_route_time != 0) + { + goto done; + } + + cluster_timeout_str = cluster_config_get(cc, + "cluster-node-timeout", &cluster_timeout_str_len); + if(cluster_timeout_str == NULL) + { + __redisClusterAsyncSetError(acc, + cc->err, cc->errstr); + goto done; + } + + cluster_timeout = hi_atoi(cluster_timeout_str, + cluster_timeout_str_len); + free(cluster_timeout_str); + if(cluster_timeout <= 0) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, + "cluster_timeout_str convert to integer error"); + goto done; + } + + now = hi_usec_now(); + if (now < 0) { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, + "get now usec time error"); + goto done; + } + + next = now + (cluster_timeout * 1000LL); + + cc->update_route_time = next; + + } + + goto done; + } + + error_type = cluster_reply_error_type(reply); + + if(error_type > CLUSTER_NOT_ERR && error_type < CLUSTER_ERR_SENTINEL) + { + cad->retry_count ++; + if(cad->retry_count > cc->max_redirect_count) + { + cad->retry_count = 0; + __redisClusterAsyncSetError(acc, + REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT, + "too many cluster redirect"); + goto done; + } + + switch(error_type) + { + case CLUSTER_ERR_MOVED: + ac_retry = actx_get_after_update_route_by_slot(acc, command->slot_num); + if(ac_retry == NULL) + { + goto done; + } + + break; + case CLUSTER_ERR_ASK: + node = node_get_by_ask_error_reply(cc, reply); + if(node == NULL) + { + __redisClusterAsyncSetError(acc, + cc->err, cc->errstr); + goto done; + } + + ac_retry = actx_get_by_node(acc, node); + if(ac_retry == NULL) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, "actx get by node error"); + goto done; + } + else if(ac_retry->err) + { + __redisClusterAsyncSetError(acc, + ac_retry->err, ac_retry->errstr); + goto done; + } + + ret = redisAsyncCommand(ac_retry, + NULL,NULL,REDIS_COMMAND_ASKING); + if(ret != REDIS_OK) + { + goto error; + } + + break; + case CLUSTER_ERR_TRYAGAIN: + case CLUSTER_ERR_CROSSSLOT: + case CLUSTER_ERR_CLUSTERDOWN: + ac_retry = ac; + + break; + default: + + goto done; + break; + } + + goto retry; + } + +done: + + if(acc->err) + { + cad->callback(acc, NULL, cad->privdata); + } + else + { + cad->callback(acc, r, cad->privdata); + } + + if(cc->err) + { + cc->err = 0; + memset(cc->errstr, '\0', strlen(cc->errstr)); + } + + if(acc->err) + { + acc->err = 0; + memset(acc->errstr, '\0', strlen(acc->errstr)); + } + + if(cad != NULL) + { + cluster_async_data_free(cad); + } + + return; + +retry: + + ret = redisAsyncFormattedCommand(ac_retry, + redisClusterAsyncCallback,cad,command->cmd,command->clen); + if(ret != REDIS_OK) + { + goto error; + } + + return; + +error: + + if(cad != NULL) + { + cluster_async_data_free(cad); + } +} + +int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, + redisClusterCallbackFn *fn, void *privdata, char *cmd, int len) { + + redisClusterContext *cc; + int status = REDIS_OK; + int slot_num; + cluster_node *node; + redisAsyncContext *ac; + struct cmd *command = NULL; + hilist *commands = NULL; + cluster_async_data *cad; + + if(acc == NULL) + { + return REDIS_ERR; + } + + cc = acc->cc; + + if(cc->err) + { + cc->err = 0; + memset(cc->errstr, '\0', strlen(cc->errstr)); + } + + if(acc->err) + { + acc->err = 0; + memset(acc->errstr, '\0', strlen(acc->errstr)); + } + + command = command_get(); + if(command == NULL) + { + __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + command->cmd = malloc(len*sizeof(*command->cmd)); + if(command->cmd == NULL) + { + __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + memcpy(command->cmd, cmd, len); + command->clen = len; + + commands = listCreate(); + if(commands == NULL) + { + __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + commands->free = listCommandFree; + + slot_num = command_format_by_slot(cc, command, commands); + + if(slot_num < 0) + { + __redisClusterAsyncSetError(acc, + cc->err, cc->errstr); + goto error; + } + else if(slot_num >= REDIS_CLUSTER_SLOTS) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER,"slot_num is out of range"); + goto error; + } + + //all keys not belong to one slot + if(listLength(commands) > 0) + { + ASSERT(listLength(commands) != 1); + + __redisClusterAsyncSetError(acc,REDIS_ERR_OTHER, + "Asynchronous API now not support multi-key command"); + goto error; + } + + node = node_get_by_table(cc, (uint32_t) slot_num); + if(node == NULL) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, "node get by table error"); + goto error; + } + + ac = actx_get_by_node(acc, node); + if(ac == NULL) + { + __redisClusterAsyncSetError(acc, + REDIS_ERR_OTHER, "actx get by node error"); + goto error; + } + else if(ac->err) + { + __redisClusterAsyncSetError(acc, ac->err, ac->errstr); + goto error; + } + + cad = cluster_async_data_get(); + if(cad == NULL) + { + __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); + goto error; + } + + cad->acc = acc; + cad->command = command; + cad->callback = fn; + cad->privdata = privdata; + + status = redisAsyncFormattedCommand(ac, + redisClusterAsyncCallback,cad,cmd,len); + if(status != REDIS_OK) + { + goto error; + } + + if(commands != NULL) + { + listRelease(commands); + } + + return REDIS_OK; + +error: + + if(command != NULL) + { + command_destroy(command); + } + + if(commands != NULL) + { + listRelease(commands); + } + + return REDIS_ERR; +} + + +int redisClustervAsyncCommand(redisClusterAsyncContext *acc, + redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap) { + int ret; + char *cmd; + int len; + + if(acc == NULL) + { + return REDIS_ERR; + } + + len = redisvFormatCommand(&cmd,format,ap); + if (len == -1) { + __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } else if (len == -2) { + __redisClusterAsyncSetError(acc,REDIS_ERR_OTHER,"Invalid format string"); + return REDIS_ERR; + } + + ret = redisClusterAsyncFormattedCommand(acc, fn, privdata, cmd, len); + + free(cmd); + + return ret; +} + +int redisClusterAsyncCommand(redisClusterAsyncContext *acc, + redisClusterCallbackFn *fn, void *privdata, const char *format, ...) { + int ret; + va_list ap; + + va_start(ap,format); + ret = redisClustervAsyncCommand(acc, fn, privdata, format, ap); + va_end(ap); + + return ret; +} + +int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, + redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) { + int ret; + char *cmd; + int len; + + len = redisFormatCommandArgv(&cmd,argc,argv,argvlen); + if (len == -1) { + __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + ret = redisClusterAsyncFormattedCommand(acc, fn, privdata, cmd, len); + + free(cmd); + + return ret; +} + +void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc) { + + redisClusterContext *cc; + redisAsyncContext *ac; + dictIterator *di; + dictEntry *de; + dict *nodes; + struct cluster_node *node; + + if(acc == NULL) + { + return; + } + + cc = acc->cc; + + nodes = cc->nodes; + + if(nodes == NULL) + { + return; + } + + di = dictGetIterator(nodes); + + while((de = dictNext(di)) != NULL) + { + node = dictGetEntryVal(de); + + ac = node->acon; + + if(ac == NULL || ac->err) + { + continue; + } + + redisAsyncDisconnect(ac); + + node->acon = NULL; + } +} + +void redisClusterAsyncFree(redisClusterAsyncContext *acc) +{ + redisClusterContext *cc; + + if(acc == NULL) + { + return; + } + + cc = acc->cc; + + redisClusterFree(cc); + + hi_free(acc); +} + diff --git a/ext/hiredis-vip-0.3.0/hircluster.h b/ext/hiredis-vip-0.3.0/hircluster.h new file mode 100644 index 00000000..5b9c5a35 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hircluster.h @@ -0,0 +1,178 @@ + +#ifndef __HIRCLUSTER_H +#define __HIRCLUSTER_H + +#include "hiredis.h" +#include "async.h" + +#define HIREDIS_VIP_MAJOR 0 +#define HIREDIS_VIP_MINOR 3 +#define HIREDIS_VIP_PATCH 0 + +#define REDIS_CLUSTER_SLOTS 16384 + +#define REDIS_ROLE_NULL 0 +#define REDIS_ROLE_MASTER 1 +#define REDIS_ROLE_SLAVE 2 + + +#define HIRCLUSTER_FLAG_NULL 0x0 +/* The flag to decide whether add slave node in + * redisClusterContext->nodes. This is set in the + * least significant bit of the flags field in + * redisClusterContext. (1000000000000) */ +#define HIRCLUSTER_FLAG_ADD_SLAVE 0x1000 +/* The flag to decide whether add open slot + * for master node. (10000000000000) */ +#define HIRCLUSTER_FLAG_ADD_OPENSLOT 0x2000 +/* The flag to decide whether get the route + * table by 'cluster slots' command. Default + * is 'cluster nodes' command.*/ +#define HIRCLUSTER_FLAG_ROUTE_USE_SLOTS 0x4000 + +struct dict; +struct hilist; + +typedef struct cluster_node +{ + sds name; + sds addr; + sds host; + int port; + uint8_t role; + uint8_t myself; /* myself ? */ + redisContext *con; + redisAsyncContext *acon; + struct hilist *slots; + struct hilist *slaves; + int failure_count; + void *data; /* Not used by hiredis */ + struct hiarray *migrating; /* copen_slot[] */ + struct hiarray *importing; /* copen_slot[] */ +}cluster_node; + +typedef struct cluster_slot +{ + uint32_t start; + uint32_t end; + cluster_node *node; /* master that this slot region belong to */ +}cluster_slot; + +typedef struct copen_slot +{ + uint32_t slot_num; /* slot number */ + int migrate; /* migrating or importing? */ + sds remote_name; /* name for the node that this slot migrating to/importing from */ + cluster_node *node; /* master that this slot belong to */ +}copen_slot; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Context for a connection to Redis cluster */ +typedef struct redisClusterContext { + int err; /* Error flags, 0 when there is no error */ + char errstr[128]; /* String representation of error when applicable */ + sds ip; + int port; + + int flags; + + enum redisConnectionType connection_type; + struct timeval *timeout; + + struct hiarray *slots; + + struct dict *nodes; + cluster_node *table[REDIS_CLUSTER_SLOTS]; + + uint64_t route_version; + + int max_redirect_count; + int retry_count; + + struct hilist *requests; + + int need_update_route; + int64_t update_route_time; +} redisClusterContext; + +redisClusterContext *redisClusterConnect(const char *addrs, int flags); +redisClusterContext *redisClusterConnectWithTimeout(const char *addrs, + const struct timeval tv, int flags); +redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags); + +void redisClusterFree(redisClusterContext *cc); + +void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); + +void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len); +void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap); +void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); +void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); + +redisContext *ctx_get_by_node(struct cluster_node *node, const struct timeval *timeout, int flags); + +int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, int len); +int redisClustervAppendCommand(redisClusterContext *cc, const char *format, va_list ap); +int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); +int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); +int redisClusterGetReply(redisClusterContext *cc, void **reply); +void redisClusterReset(redisClusterContext *cc); + +int cluster_update_route(redisClusterContext *cc); +int test_cluster_update_route(redisClusterContext *cc); +struct dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, int flags); +struct dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, int flags); + + +/*############redis cluster async############*/ + +struct redisClusterAsyncContext; + +typedef int (adapterAttachFn)(redisAsyncContext*, void*); + +typedef void (redisClusterCallbackFn)(struct redisClusterAsyncContext*, void*, void*); + +/* Context for an async connection to Redis */ +typedef struct redisClusterAsyncContext { + + redisClusterContext *cc; + + /* Setup error flags so they can be used directly. */ + int err; + char errstr[128]; /* String representation of error when applicable */ + + /* Not used by hiredis */ + void *data; + + void *adapter; + adapterAttachFn *attach_fn; + + /* Called when either the connection is terminated due to an error or per + * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ + redisDisconnectCallback *onDisconnect; + + /* Called when the first write event was received. */ + redisConnectCallback *onConnect; + +} redisClusterAsyncContext; + +redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags); +int redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn); +int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); +int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, char *cmd, int len); +int redisClustervAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap); +int redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, ...); +int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); +void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); +void redisClusterAsyncFree(redisClusterAsyncContext *acc); + +redisAsyncContext *actx_get_by_node(redisClusterAsyncContext *acc, cluster_node *node); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/hiredis-vip-0.3.0/hiredis.c b/ext/hiredis-vip-0.3.0/hiredis.c new file mode 100644 index 00000000..73d0251b --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hiredis.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include + +#include "hiredis.h" +#include "net.h" +#include "sds.h" + +static redisReply *createReplyObject(int type); +static void *createStringObject(const redisReadTask *task, char *str, size_t len); +static void *createArrayObject(const redisReadTask *task, int elements); +static void *createIntegerObject(const redisReadTask *task, long long value); +static void *createNilObject(const redisReadTask *task); + +/* Default set of functions to build the reply. Keep in mind that such a + * function returning NULL is interpreted as OOM. */ +static redisReplyObjectFunctions defaultFunctions = { + createStringObject, + createArrayObject, + createIntegerObject, + createNilObject, + freeReplyObject +}; + +/* Create a reply object */ +static redisReply *createReplyObject(int type) { + redisReply *r = calloc(1,sizeof(*r)); + + if (r == NULL) + return NULL; + + r->type = type; + return r; +} + +/* Free a reply object */ +void freeReplyObject(void *reply) { + redisReply *r = reply; + size_t j; + + if (r == NULL) + return; + + switch(r->type) { + case REDIS_REPLY_INTEGER: + break; /* Nothing to free */ + case REDIS_REPLY_ARRAY: + if (r->element != NULL) { + for (j = 0; j < r->elements; j++) + if (r->element[j] != NULL) + freeReplyObject(r->element[j]); + free(r->element); + } + break; + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_STRING: + if (r->str != NULL) + free(r->str); + break; + } + free(r); +} + +static void *createStringObject(const redisReadTask *task, char *str, size_t len) { + redisReply *r, *parent; + char *buf; + + r = createReplyObject(task->type); + if (r == NULL) + return NULL; + + buf = malloc(len+1); + if (buf == NULL) { + freeReplyObject(r); + return NULL; + } + + assert(task->type == REDIS_REPLY_ERROR || + task->type == REDIS_REPLY_STATUS || + task->type == REDIS_REPLY_STRING); + + /* Copy string value */ + memcpy(buf,str,len); + buf[len] = '\0'; + r->str = buf; + r->len = len; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +static void *createArrayObject(const redisReadTask *task, int elements) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_ARRAY); + if (r == NULL) + return NULL; + + if (elements > 0) { + r->element = calloc(elements,sizeof(redisReply*)); + if (r->element == NULL) { + freeReplyObject(r); + return NULL; + } + } + + r->elements = elements; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +static void *createIntegerObject(const redisReadTask *task, long long value) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_INTEGER); + if (r == NULL) + return NULL; + + r->integer = value; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +static void *createNilObject(const redisReadTask *task) { + redisReply *r, *parent; + + r = createReplyObject(REDIS_REPLY_NIL); + if (r == NULL) + return NULL; + + if (task->parent) { + parent = task->parent->obj; + assert(parent->type == REDIS_REPLY_ARRAY); + parent->element[task->idx] = r; + } + return r; +} + +/* Return the number of digits of 'v' when converted to string in radix 10. + * Implementation borrowed from link in redis/src/util.c:string2ll(). */ +static uint32_t countDigits(uint64_t v) { + uint32_t result = 1; + for (;;) { + if (v < 10) return result; + if (v < 100) return result + 1; + if (v < 1000) return result + 2; + if (v < 10000) return result + 3; + v /= 10000U; + result += 4; + } +} + +/* Helper that calculates the bulk length given a certain string length. */ +static size_t bulklen(size_t len) { + return 1+countDigits(len)+2+len+2; +} + +int redisvFormatCommand(char **target, const char *format, va_list ap) { + const char *c = format; + char *cmd = NULL; /* final command */ + int pos; /* position in final command */ + sds curarg, newarg; /* current argument */ + int touched = 0; /* was the current argument touched? */ + char **curargv = NULL, **newargv = NULL; + int argc = 0; + int totlen = 0; + int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */ + int j; + + /* Abort if there is not target to set */ + if (target == NULL) + return -1; + + /* Build the command string accordingly to protocol */ + curarg = sdsempty(); + if (curarg == NULL) + return -1; + + while(*c != '\0') { + if (*c != '%' || c[1] == '\0') { + if (*c == ' ') { + if (touched) { + newargv = realloc(curargv,sizeof(char*)*(argc+1)); + if (newargv == NULL) goto memory_err; + curargv = newargv; + curargv[argc++] = curarg; + totlen += bulklen(sdslen(curarg)); + + /* curarg is put in argv so it can be overwritten. */ + curarg = sdsempty(); + if (curarg == NULL) goto memory_err; + touched = 0; + } + } else { + newarg = sdscatlen(curarg,c,1); + if (newarg == NULL) goto memory_err; + curarg = newarg; + touched = 1; + } + } else { + char *arg; + size_t size; + + /* Set newarg so it can be checked even if it is not touched. */ + newarg = curarg; + + switch(c[1]) { + case 's': + arg = va_arg(ap,char*); + size = strlen(arg); + if (size > 0) + newarg = sdscatlen(curarg,arg,size); + break; + case 'b': + arg = va_arg(ap,char*); + size = va_arg(ap,size_t); + if (size > 0) + newarg = sdscatlen(curarg,arg,size); + break; + case '%': + newarg = sdscat(curarg,"%"); + break; + default: + /* Try to detect printf format */ + { + static const char intfmts[] = "diouxX"; + static const char flags[] = "#0-+ "; + char _format[16]; + const char *_p = c+1; + size_t _l = 0; + va_list _cpy; + + /* Flags */ + while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; + + /* Field width */ + while (*_p != '\0' && isdigit(*_p)) _p++; + + /* Precision */ + if (*_p == '.') { + _p++; + while (*_p != '\0' && isdigit(*_p)) _p++; + } + + /* Copy va_list before consuming with va_arg */ + va_copy(_cpy,ap); + + /* Integer conversion (without modifiers) */ + if (strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); + goto fmt_valid; + } + + /* Double conversion (without modifiers) */ + if (strchr("eEfFgGaA",*_p) != NULL) { + va_arg(ap,double); + goto fmt_valid; + } + + /* Size: char */ + if (_p[0] == 'h' && _p[1] == 'h') { + _p += 2; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); /* char gets promoted to int */ + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: short */ + if (_p[0] == 'h') { + _p += 1; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,int); /* short gets promoted to int */ + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: long long */ + if (_p[0] == 'l' && _p[1] == 'l') { + _p += 2; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,long long); + goto fmt_valid; + } + goto fmt_invalid; + } + + /* Size: long */ + if (_p[0] == 'l') { + _p += 1; + if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { + va_arg(ap,long); + goto fmt_valid; + } + goto fmt_invalid; + } + + fmt_invalid: + va_end(_cpy); + goto format_err; + + fmt_valid: + _l = (_p+1)-c; + if (_l < sizeof(_format)-2) { + memcpy(_format,c,_l); + _format[_l] = '\0'; + newarg = sdscatvprintf(curarg,_format,_cpy); + + /* Update current position (note: outer blocks + * increment c twice so compensate here) */ + c = _p-1; + } + + va_end(_cpy); + break; + } + } + + if (newarg == NULL) goto memory_err; + curarg = newarg; + + touched = 1; + c++; + } + c++; + } + + /* Add the last argument if needed */ + if (touched) { + newargv = realloc(curargv,sizeof(char*)*(argc+1)); + if (newargv == NULL) goto memory_err; + curargv = newargv; + curargv[argc++] = curarg; + totlen += bulklen(sdslen(curarg)); + } else { + sdsfree(curarg); + } + + /* Clear curarg because it was put in curargv or was free'd. */ + curarg = NULL; + + /* Add bytes needed to hold multi bulk count */ + totlen += 1+countDigits(argc)+2; + + /* Build the command at protocol level */ + cmd = malloc(totlen+1); + if (cmd == NULL) goto memory_err; + + pos = sprintf(cmd,"*%d\r\n",argc); + for (j = 0; j < argc; j++) { + pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); + memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); + pos += sdslen(curargv[j]); + sdsfree(curargv[j]); + cmd[pos++] = '\r'; + cmd[pos++] = '\n'; + } + assert(pos == totlen); + cmd[pos] = '\0'; + + free(curargv); + *target = cmd; + return totlen; + +format_err: + error_type = -2; + goto cleanup; + +memory_err: + error_type = -1; + goto cleanup; + +cleanup: + if (curargv) { + while(argc--) + sdsfree(curargv[argc]); + free(curargv); + } + + sdsfree(curarg); + + /* No need to check cmd since it is the last statement that can fail, + * but do it anyway to be as defensive as possible. */ + if (cmd != NULL) + free(cmd); + + return error_type; +} + +/* Format a command according to the Redis protocol. This function + * takes a format similar to printf: + * + * %s represents a C null terminated string you want to interpolate + * %b represents a binary safe string + * + * When using %b you need to provide both the pointer to the string + * and the length in bytes as a size_t. Examples: + * + * len = redisFormatCommand(target, "GET %s", mykey); + * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen); + */ +int redisFormatCommand(char **target, const char *format, ...) { + va_list ap; + int len; + va_start(ap,format); + len = redisvFormatCommand(target,format,ap); + va_end(ap); + + /* The API says "-1" means bad result, but we now also return "-2" in some + * cases. Force the return value to always be -1. */ + if (len < 0) + len = -1; + + return len; +} + +/* Format a command according to the Redis protocol using an sds string and + * sdscatfmt for the processing of arguments. This function takes the + * number of arguments, an array with arguments and an array with their + * lengths. If the latter is set to NULL, strlen will be used to compute the + * argument lengths. + */ +int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, + const size_t *argvlen) +{ + sds cmd; + unsigned long long totlen; + int j; + size_t len; + + /* Abort on a NULL target */ + if (target == NULL) + return -1; + + /* Calculate our total size */ + totlen = 1+countDigits(argc)+2; + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + totlen += bulklen(len); + } + + /* Use an SDS string for command construction */ + cmd = sdsempty(); + if (cmd == NULL) + return -1; + + /* We already know how much storage we need */ + cmd = sdsMakeRoomFor(cmd, totlen); + if (cmd == NULL) + return -1; + + /* Construct command */ + cmd = sdscatfmt(cmd, "*%i\r\n", argc); + for (j=0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + cmd = sdscatfmt(cmd, "$%T\r\n", len); + cmd = sdscatlen(cmd, argv[j], len); + cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); + } + + assert(sdslen(cmd)==totlen); + + *target = cmd; + return totlen; +} + +void redisFreeSdsCommand(sds cmd) { + sdsfree(cmd); +} + +/* Format a command according to the Redis protocol. This function takes the + * number of arguments, an array with arguments and an array with their + * lengths. If the latter is set to NULL, strlen will be used to compute the + * argument lengths. + */ +int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) { + char *cmd = NULL; /* final command */ + int pos; /* position in final command */ + size_t len; + int totlen, j; + + /* Abort on a NULL target */ + if (target == NULL) + return -1; + + /* Calculate number of bytes needed for the command */ + totlen = 1+countDigits(argc)+2; + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + totlen += bulklen(len); + } + + /* Build the command at protocol level */ + cmd = malloc(totlen+1); + if (cmd == NULL) + return -1; + + pos = sprintf(cmd,"*%d\r\n",argc); + for (j = 0; j < argc; j++) { + len = argvlen ? argvlen[j] : strlen(argv[j]); + pos += sprintf(cmd+pos,"$%zu\r\n",len); + memcpy(cmd+pos,argv[j],len); + pos += len; + cmd[pos++] = '\r'; + cmd[pos++] = '\n'; + } + assert(pos == totlen); + cmd[pos] = '\0'; + + *target = cmd; + return totlen; +} + +void redisFreeCommand(char *cmd) { + free(cmd); +} + +void __redisSetError(redisContext *c, int type, const char *str) { + size_t len; + + c->err = type; + if (str != NULL) { + len = strlen(str); + len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1); + memcpy(c->errstr,str,len); + c->errstr[len] = '\0'; + } else { + /* Only REDIS_ERR_IO may lack a description! */ + assert(type == REDIS_ERR_IO); + __redis_strerror_r(errno, c->errstr, sizeof(c->errstr)); + } +} + +redisReader *redisReaderCreate(void) { + return redisReaderCreateWithFunctions(&defaultFunctions); +} + +static redisContext *redisContextInit(void) { + redisContext *c; + + c = calloc(1,sizeof(redisContext)); + if (c == NULL) + return NULL; + + c->err = 0; + c->errstr[0] = '\0'; + c->obuf = sdsempty(); + c->reader = redisReaderCreate(); + c->tcp.host = NULL; + c->tcp.source_addr = NULL; + c->unix_sock.path = NULL; + c->timeout = NULL; + + if (c->obuf == NULL || c->reader == NULL) { + redisFree(c); + return NULL; + } + + return c; +} + +void redisFree(redisContext *c) { + if (c == NULL) + return; + if (c->fd > 0) + close(c->fd); + if (c->obuf != NULL) + sdsfree(c->obuf); + if (c->reader != NULL) + redisReaderFree(c->reader); + if (c->tcp.host) + free(c->tcp.host); + if (c->tcp.source_addr) + free(c->tcp.source_addr); + if (c->unix_sock.path) + free(c->unix_sock.path); + if (c->timeout) + free(c->timeout); + free(c); +} + +int redisFreeKeepFd(redisContext *c) { + int fd = c->fd; + c->fd = -1; + redisFree(c); + return fd; +} + +int redisReconnect(redisContext *c) { + c->err = 0; + memset(c->errstr, '\0', strlen(c->errstr)); + + if (c->fd > 0) { + close(c->fd); + } + + sdsfree(c->obuf); + redisReaderFree(c->reader); + + c->obuf = sdsempty(); + c->reader = redisReaderCreate(); + + if (c->connection_type == REDIS_CONN_TCP) { + return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, + c->timeout, c->tcp.source_addr); + } else if (c->connection_type == REDIS_CONN_UNIX) { + return redisContextConnectUnix(c, c->unix_sock.path, c->timeout); + } else { + /* Something bad happened here and shouldn't have. There isn't + enough information in the context to reconnect. */ + __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect"); + } + + return REDIS_ERR; +} + +/* Connect to a Redis instance. On error the field error in the returned + * context will be set to the return value of the error function. + * When no set of reply functions is given, the default set will be used. */ +redisContext *redisConnect(const char *ip, int port) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectTcp(c,ip,port,NULL); + return c; +} + +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectTcp(c,ip,port,&tv); + return c; +} + +redisContext *redisConnectNonBlock(const char *ip, int port) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags &= ~REDIS_BLOCK; + redisContextConnectTcp(c,ip,port,NULL); + return c; +} + +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisContextInit(); + c->flags &= ~REDIS_BLOCK; + redisContextConnectBindTcp(c,ip,port,NULL,source_addr); + return c; +} + +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr) { + redisContext *c = redisContextInit(); + c->flags &= ~REDIS_BLOCK; + c->flags |= REDIS_REUSEADDR; + redisContextConnectBindTcp(c,ip,port,NULL,source_addr); + return c; +} + +redisContext *redisConnectUnix(const char *path) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectUnix(c,path,NULL); + return c; +} + +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags |= REDIS_BLOCK; + redisContextConnectUnix(c,path,&tv); + return c; +} + +redisContext *redisConnectUnixNonBlock(const char *path) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->flags &= ~REDIS_BLOCK; + redisContextConnectUnix(c,path,NULL); + return c; +} + +redisContext *redisConnectFd(int fd) { + redisContext *c; + + c = redisContextInit(); + if (c == NULL) + return NULL; + + c->fd = fd; + c->flags |= REDIS_BLOCK | REDIS_CONNECTED; + return c; +} + +/* Set read/write timeout on a blocking socket. */ +int redisSetTimeout(redisContext *c, const struct timeval tv) { + if (c->flags & REDIS_BLOCK) + return redisContextSetTimeout(c,tv); + return REDIS_ERR; +} + +/* Enable connection KeepAlive. */ +int redisEnableKeepAlive(redisContext *c) { + if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK) + return REDIS_ERR; + return REDIS_OK; +} + +/* Use this function to handle a read event on the descriptor. It will try + * and read some bytes from the socket and feed them to the reply parser. + * + * After this function is called, you may use redisContextReadReply to + * see if there is a reply available. */ +int redisBufferRead(redisContext *c) { + char buf[1024*16]; + int nread; + + /* Return early when the context has seen an error. */ + if (c->err) + return REDIS_ERR; + + nread = read(c->fd,buf,sizeof(buf)); + if (nread == -1) { + if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { + /* Try again later */ + } else { + __redisSetError(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + } else if (nread == 0) { + __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection"); + return REDIS_ERR; + } else { + if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) { + __redisSetError(c,c->reader->err,c->reader->errstr); + return REDIS_ERR; + } + } + return REDIS_OK; +} + +/* Write the output buffer to the socket. + * + * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was + * succesfully written to the socket. When the buffer is empty after the + * write operation, "done" is set to 1 (if given). + * + * Returns REDIS_ERR if an error occured trying to write and sets + * c->errstr to hold the appropriate error string. + */ +int redisBufferWrite(redisContext *c, int *done) { + int nwritten; + + /* Return early when the context has seen an error. */ + if (c->err) + return REDIS_ERR; + + if (sdslen(c->obuf) > 0) { + nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); + if (nwritten == -1) { + if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { + /* Try again later */ + } else { + __redisSetError(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + } else if (nwritten > 0) { + if (nwritten == (signed)sdslen(c->obuf)) { + sdsfree(c->obuf); + c->obuf = sdsempty(); + } else { + sdsrange(c->obuf,nwritten,-1); + } + } + } + if (done != NULL) *done = (sdslen(c->obuf) == 0); + return REDIS_OK; +} + +/* Internal helper function to try and get a reply from the reader, + * or set an error in the context otherwise. */ +int redisGetReplyFromReader(redisContext *c, void **reply) { + if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) { + __redisSetError(c,c->reader->err,c->reader->errstr); + return REDIS_ERR; + } + return REDIS_OK; +} + +int redisGetReply(redisContext *c, void **reply) { + int wdone = 0; + void *aux = NULL; + + /* Try to read pending replies */ + if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) + return REDIS_ERR; + + /* For the blocking context, flush output buffer and read reply */ + if (aux == NULL && c->flags & REDIS_BLOCK) { + /* Write until done */ + do { + if (redisBufferWrite(c,&wdone) == REDIS_ERR) + return REDIS_ERR; + } while (!wdone); + + /* Read until there is a reply */ + do { + if (redisBufferRead(c) == REDIS_ERR) + return REDIS_ERR; + if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) + return REDIS_ERR; + } while (aux == NULL); + } + + /* Set reply object */ + if (reply != NULL) *reply = aux; + return REDIS_OK; +} + + +/* Helper function for the redisAppendCommand* family of functions. + * + * Write a formatted command to the output buffer. When this family + * is used, you need to call redisGetReply yourself to retrieve + * the reply (or replies in pub/sub). + */ +int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) { + sds newbuf; + + newbuf = sdscatlen(c->obuf,cmd,len); + if (newbuf == NULL) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + c->obuf = newbuf; + return REDIS_OK; +} + +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) { + + if (__redisAppendCommand(c, cmd, len) != REDIS_OK) { + return REDIS_ERR; + } + + return REDIS_OK; +} + +int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { + char *cmd; + int len; + + len = redisvFormatCommand(&cmd,format,ap); + if (len == -1) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } else if (len == -2) { + __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string"); + return REDIS_ERR; + } + + if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { + free(cmd); + return REDIS_ERR; + } + + free(cmd); + return REDIS_OK; +} + +int redisAppendCommand(redisContext *c, const char *format, ...) { + va_list ap; + int ret; + + va_start(ap,format); + ret = redisvAppendCommand(c,format,ap); + va_end(ap); + return ret; +} + +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { + sds cmd; + int len; + + len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); + if (len == -1) { + __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); + return REDIS_ERR; + } + + if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { + sdsfree(cmd); + return REDIS_ERR; + } + + sdsfree(cmd); + return REDIS_OK; +} + +/* Helper function for the redisCommand* family of functions. + * + * Write a formatted command to the output buffer. If the given context is + * blocking, immediately read the reply into the "reply" pointer. When the + * context is non-blocking, the "reply" pointer will not be used and the + * command is simply appended to the write buffer. + * + * Returns the reply when a reply was succesfully retrieved. Returns NULL + * otherwise. When NULL is returned in a blocking context, the error field + * in the context will be set. + */ +static void *__redisBlockForReply(redisContext *c) { + void *reply; + + if (c->flags & REDIS_BLOCK) { + if (redisGetReply(c,&reply) != REDIS_OK) + return NULL; + return reply; + } + return NULL; +} + +void *redisvCommand(redisContext *c, const char *format, va_list ap) { + if (redisvAppendCommand(c,format,ap) != REDIS_OK) + return NULL; + return __redisBlockForReply(c); +} + +void *redisCommand(redisContext *c, const char *format, ...) { + va_list ap; + void *reply = NULL; + va_start(ap,format); + reply = redisvCommand(c,format,ap); + va_end(ap); + return reply; +} + +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { + if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK) + return NULL; + return __redisBlockForReply(c); +} diff --git a/ext/hiredis-vip-0.3.0/hiredis.h b/ext/hiredis-vip-0.3.0/hiredis.h new file mode 100644 index 00000000..87f7366f --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hiredis.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_H +#define __HIREDIS_H +#include "read.h" +#include /* for va_list */ +#include /* for struct timeval */ +#include /* uintXX_t, etc */ +#include "sds.h" /* for sds */ + +#define HIREDIS_MAJOR 0 +#define HIREDIS_MINOR 13 +#define HIREDIS_PATCH 1 + +/* Connection type can be blocking or non-blocking and is set in the + * least significant bit of the flags field in redisContext. */ +#define REDIS_BLOCK 0x1 + +/* Connection may be disconnected before being free'd. The second bit + * in the flags field is set when the context is connected. */ +#define REDIS_CONNECTED 0x2 + +/* The async API might try to disconnect cleanly and flush the output + * buffer and read all subsequent replies before disconnecting. + * This flag means no new commands can come in and the connection + * should be terminated once all replies have been read. */ +#define REDIS_DISCONNECTING 0x4 + +/* Flag specific to the async API which means that the context should be clean + * up as soon as possible. */ +#define REDIS_FREEING 0x8 + +/* Flag that is set when an async callback is executed. */ +#define REDIS_IN_CALLBACK 0x10 + +/* Flag that is set when the async context has one or more subscriptions. */ +#define REDIS_SUBSCRIBED 0x20 + +/* Flag that is set when monitor mode is active */ +#define REDIS_MONITORING 0x40 + +/* Flag that is set when we should set SO_REUSEADDR before calling bind() */ +#define REDIS_REUSEADDR 0x80 + +#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ + +/* number of times we retry to connect in the case of EADDRNOTAVAIL and + * SO_REUSEADDR is being used. */ +#define REDIS_CONNECT_RETRIES 10 + +/* strerror_r has two completely different prototypes and behaviors + * depending on system issues, so we need to operate on the error buffer + * differently depending on which strerror_r we're using. */ +#ifndef _GNU_SOURCE +/* "regular" POSIX strerror_r that does the right thing. */ +#define __redis_strerror_r(errno, buf, len) \ + do { \ + strerror_r((errno), (buf), (len)); \ + } while (0) +#else +/* "bad" GNU strerror_r we need to clean up after. */ +#define __redis_strerror_r(errno, buf, len) \ + do { \ + char *err_str = strerror_r((errno), (buf), (len)); \ + /* If return value _isn't_ the start of the buffer we passed in, \ + * then GNU strerror_r returned an internal static buffer and we \ + * need to copy the result into our private buffer. */ \ + if (err_str != (buf)) { \ + buf[(len)] = '\0'; \ + strncat((buf), err_str, ((len) - 1)); \ + } \ + } while (0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the reply object returned by redisCommand() */ +typedef struct redisReply { + int type; /* REDIS_REPLY_* */ + long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ + int len; /* Length of string */ + char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ + size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ + struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ +} redisReply; + +redisReader *redisReaderCreate(void); + +/* Function to free the reply objects hiredis returns by default. */ +void freeReplyObject(void *reply); + +/* Functions to format a command according to the protocol. */ +int redisvFormatCommand(char **target, const char *format, va_list ap); +int redisFormatCommand(char **target, const char *format, ...); +int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); +int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); +void redisFreeCommand(char *cmd); +void redisFreeSdsCommand(sds cmd); + +enum redisConnectionType { + REDIS_CONN_TCP, + REDIS_CONN_UNIX, +}; + +/* Context for a connection to Redis */ +typedef struct redisContext { + int err; /* Error flags, 0 when there is no error */ + char errstr[128]; /* String representation of error when applicable */ + int fd; + int flags; + char *obuf; /* Write buffer */ + redisReader *reader; /* Protocol reader */ + + enum redisConnectionType connection_type; + struct timeval *timeout; + + struct { + char *host; + char *source_addr; + int port; + } tcp; + + struct { + char *path; + } unix_sock; +} redisContext; + +redisContext *redisConnect(const char *ip, int port); +redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); +redisContext *redisConnectNonBlock(const char *ip, int port); +redisContext *redisConnectBindNonBlock(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, + const char *source_addr); +redisContext *redisConnectUnix(const char *path); +redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); +redisContext *redisConnectUnixNonBlock(const char *path); +redisContext *redisConnectFd(int fd); + +/** + * Reconnect the given context using the saved information. + * + * This re-uses the exact same connect options as in the initial connection. + * host, ip (or path), timeout and bind address are reused, + * flags are used unmodified from the existing context. + * + * Returns REDIS_OK on successfull connect or REDIS_ERR otherwise. + */ +int redisReconnect(redisContext *c); + +int redisSetTimeout(redisContext *c, const struct timeval tv); +int redisEnableKeepAlive(redisContext *c); +void redisFree(redisContext *c); +int redisFreeKeepFd(redisContext *c); +int redisBufferRead(redisContext *c); +int redisBufferWrite(redisContext *c, int *done); + +/* In a blocking context, this function first checks if there are unconsumed + * replies to return and returns one if so. Otherwise, it flushes the output + * buffer to the socket and reads until it has a reply. In a non-blocking + * context, it will return unconsumed replies until there are no more. */ +int redisGetReply(redisContext *c, void **reply); +int redisGetReplyFromReader(redisContext *c, void **reply); + +/* Write a formatted command to the output buffer. Use these functions in blocking mode + * to get a pipeline of commands. */ +int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); + +/* Write a command to the output buffer. Use these functions in blocking mode + * to get a pipeline of commands. */ +int redisvAppendCommand(redisContext *c, const char *format, va_list ap); +int redisAppendCommand(redisContext *c, const char *format, ...); +int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + +/* Issue a command to Redis. In a blocking context, it is identical to calling + * redisAppendCommand, followed by redisGetReply. The function will return + * NULL if there was an error in performing the request, otherwise it will + * return the reply. In a non-blocking context, it is identical to calling + * only redisAppendCommand and will always return NULL. */ +void *redisvCommand(redisContext *c, const char *format, va_list ap); +void *redisCommand(redisContext *c, const char *format, ...); +void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/hiredis-vip-0.3.0/hiutil.c b/ext/hiredis-vip-0.3.0/hiutil.c new file mode 100644 index 00000000..d10cdace --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hiutil.c @@ -0,0 +1,554 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +#include "hiutil.h" + +#ifdef HI_HAVE_BACKTRACE +# include +#endif + +int +hi_set_blocking(int sd) +{ + int flags; + + flags = fcntl(sd, F_GETFL, 0); + if (flags < 0) { + return flags; + } + + return fcntl(sd, F_SETFL, flags & ~O_NONBLOCK); +} + +int +hi_set_nonblocking(int sd) +{ + int flags; + + flags = fcntl(sd, F_GETFL, 0); + if (flags < 0) { + return flags; + } + + return fcntl(sd, F_SETFL, flags | O_NONBLOCK); +} + +int +hi_set_reuseaddr(int sd) +{ + int reuse; + socklen_t len; + + reuse = 1; + len = sizeof(reuse); + + return setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, len); +} + +/* + * Disable Nagle algorithm on TCP socket. + * + * This option helps to minimize transmit latency by disabling coalescing + * of data to fill up a TCP segment inside the kernel. Sockets with this + * option must use readv() or writev() to do data transfer in bulk and + * hence avoid the overhead of small packets. + */ +int +hi_set_tcpnodelay(int sd) +{ + int nodelay; + socklen_t len; + + nodelay = 1; + len = sizeof(nodelay); + + return setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, len); +} + +int +hi_set_linger(int sd, int timeout) +{ + struct linger linger; + socklen_t len; + + linger.l_onoff = 1; + linger.l_linger = timeout; + + len = sizeof(linger); + + return setsockopt(sd, SOL_SOCKET, SO_LINGER, &linger, len); +} + +int +hi_set_sndbuf(int sd, int size) +{ + socklen_t len; + + len = sizeof(size); + + return setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, len); +} + +int +hi_set_rcvbuf(int sd, int size) +{ + socklen_t len; + + len = sizeof(size); + + return setsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, len); +} + +int +hi_get_soerror(int sd) +{ + int status, err; + socklen_t len; + + err = 0; + len = sizeof(err); + + status = getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len); + if (status == 0) { + errno = err; + } + + return status; +} + +int +hi_get_sndbuf(int sd) +{ + int status, size; + socklen_t len; + + size = 0; + len = sizeof(size); + + status = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, &len); + if (status < 0) { + return status; + } + + return size; +} + +int +hi_get_rcvbuf(int sd) +{ + int status, size; + socklen_t len; + + size = 0; + len = sizeof(size); + + status = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, &len); + if (status < 0) { + return status; + } + + return size; +} + +int +_hi_atoi(uint8_t *line, size_t n) +{ + int value; + + if (n == 0) { + return -1; + } + + for (value = 0; n--; line++) { + if (*line < '0' || *line > '9') { + return -1; + } + + value = value * 10 + (*line - '0'); + } + + if (value < 0) { + return -1; + } + + return value; +} + +void +_hi_itoa(uint8_t *s, int num) +{ + uint8_t c; + uint8_t sign = 0; + + if(s == NULL) + { + return; + } + + uint32_t len, i; + len = 0; + + if(num < 0) + { + sign = 1; + num = abs(num); + } + else if(num == 0) + { + s[len++] = '0'; + return; + } + + while(num % 10 || num /10) + { + c = num %10 + '0'; + num = num /10; + s[len+1] = s[len]; + s[len] = c; + len ++; + } + + if(sign == 1) + { + s[len++] = '-'; + } + + s[len] = '\0'; + + for(i = 0; i < len/2; i ++) + { + c = s[i]; + s[i] = s[len - i -1]; + s[len - i -1] = c; + } + +} + + +int +hi_valid_port(int n) +{ + if (n < 1 || n > UINT16_MAX) { + return 0; + } + + return 1; +} + +int _uint_len(uint32_t num) +{ + int n = 0; + + if(num == 0) + { + return 1; + } + + while(num != 0) + { + n ++; + num /= 10; + } + + return n; +} + +void * +_hi_alloc(size_t size, const char *name, int line) +{ + void *p; + + ASSERT(size != 0); + + p = malloc(size); + + if(name == NULL && line == 1) + { + + } + + return p; +} + +void * +_hi_zalloc(size_t size, const char *name, int line) +{ + void *p; + + p = _hi_alloc(size, name, line); + if (p != NULL) { + memset(p, 0, size); + } + + return p; +} + +void * +_hi_calloc(size_t nmemb, size_t size, const char *name, int line) +{ + return _hi_zalloc(nmemb * size, name, line); +} + +void * +_hi_realloc(void *ptr, size_t size, const char *name, int line) +{ + void *p; + + ASSERT(size != 0); + + p = realloc(ptr, size); + + if(name == NULL && line == 1) + { + + } + + return p; +} + +void +_hi_free(void *ptr, const char *name, int line) +{ + ASSERT(ptr != NULL); + + if(name == NULL && line == 1) + { + + } + + free(ptr); +} + +void +hi_stacktrace(int skip_count) +{ + if(skip_count > 0) + { + + } + +#ifdef HI_HAVE_BACKTRACE + void *stack[64]; + char **symbols; + int size, i, j; + + size = backtrace(stack, 64); + symbols = backtrace_symbols(stack, size); + if (symbols == NULL) { + return; + } + + skip_count++; /* skip the current frame also */ + + for (i = skip_count, j = 0; i < size; i++, j++) { + printf("[%d] %s\n", j, symbols[i]); + } + + free(symbols); +#endif +} + +void +hi_stacktrace_fd(int fd) +{ + if(fd > 0) + { + + } +#ifdef HI_HAVE_BACKTRACE + void *stack[64]; + int size; + + size = backtrace(stack, 64); + backtrace_symbols_fd(stack, size, fd); +#endif +} + +void +hi_assert(const char *cond, const char *file, int line, int panic) +{ + + printf("File: %s Line: %d: %s\n", file, line, cond); + + if (panic) { + hi_stacktrace(1); + abort(); + } + abort(); +} + +int +_vscnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int n; + + n = vsnprintf(buf, size, fmt, args); + + /* + * The return value is the number of characters which would be written + * into buf not including the trailing '\0'. If size is == 0 the + * function returns 0. + * + * On error, the function also returns 0. This is to allow idiom such + * as len += _vscnprintf(...) + * + * See: http://lwn.net/Articles/69419/ + */ + if (n <= 0) { + return 0; + } + + if (n < (int) size) { + return n; + } + + return (int)(size - 1); +} + +int +_scnprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list args; + int n; + + va_start(args, fmt); + n = _vscnprintf(buf, size, fmt, args); + va_end(args); + + return n; +} + +/* + * Send n bytes on a blocking descriptor + */ +ssize_t +_hi_sendn(int sd, const void *vptr, size_t n) +{ + size_t nleft; + ssize_t nsend; + const char *ptr; + + ptr = vptr; + nleft = n; + while (nleft > 0) { + nsend = send(sd, ptr, nleft, 0); + if (nsend < 0) { + if (errno == EINTR) { + continue; + } + return nsend; + } + if (nsend == 0) { + return -1; + } + + nleft -= (size_t)nsend; + ptr += nsend; + } + + return (ssize_t)n; +} + +/* + * Recv n bytes from a blocking descriptor + */ +ssize_t +_hi_recvn(int sd, void *vptr, size_t n) +{ + size_t nleft; + ssize_t nrecv; + char *ptr; + + ptr = vptr; + nleft = n; + while (nleft > 0) { + nrecv = recv(sd, ptr, nleft, 0); + if (nrecv < 0) { + if (errno == EINTR) { + continue; + } + return nrecv; + } + if (nrecv == 0) { + break; + } + + nleft -= (size_t)nrecv; + ptr += nrecv; + } + + return (ssize_t)(n - nleft); +} + +/* + * Return the current time in microseconds since Epoch + */ +int64_t +hi_usec_now(void) +{ + struct timeval now; + int64_t usec; + int status; + + status = gettimeofday(&now, NULL); + if (status < 0) { + return -1; + } + + usec = (int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec; + + return usec; +} + +/* + * Return the current time in milliseconds since Epoch + */ +int64_t +hi_msec_now(void) +{ + return hi_usec_now() / 1000LL; +} + +void print_string_with_length(char *s, size_t len) +{ + char *token; + for(token = s; token <= s + len; token ++) + { + printf("%c", *token); + } + printf("\n"); +} + +void print_string_with_length_fix_CRLF(char *s, size_t len) +{ + char *token; + for(token = s; token < s + len; token ++) + { + if(*token == CR) + { + printf("\\r"); + } + else if(*token == LF) + { + printf("\\n"); + } + else + { + printf("%c", *token); + } + } + printf("\n"); +} + diff --git a/ext/hiredis-vip-0.3.0/hiutil.h b/ext/hiredis-vip-0.3.0/hiutil.h new file mode 100644 index 00000000..d9e1ddb0 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/hiutil.h @@ -0,0 +1,265 @@ +#ifndef __HIUTIL_H_ +#define __HIUTIL_H_ + +#include +#include +#include + +#define HI_OK 0 +#define HI_ERROR -1 +#define HI_EAGAIN -2 +#define HI_ENOMEM -3 + +typedef int rstatus_t; /* return type */ + +#define LF (uint8_t) 10 +#define CR (uint8_t) 13 +#define CRLF "\x0d\x0a" +#define CRLF_LEN (sizeof("\x0d\x0a") - 1) + +#define NELEMS(a) ((sizeof(a)) / sizeof((a)[0])) + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define SQUARE(d) ((d) * (d)) +#define VAR(s, s2, n) (((n) < 2) ? 0.0 : ((s2) - SQUARE(s)/(n)) / ((n) - 1)) +#define STDDEV(s, s2, n) (((n) < 2) ? 0.0 : sqrt(VAR((s), (s2), (n)))) + +#define HI_INET4_ADDRSTRLEN (sizeof("255.255.255.255") - 1) +#define HI_INET6_ADDRSTRLEN \ + (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) +#define HI_INET_ADDRSTRLEN MAX(HI_INET4_ADDRSTRLEN, HI_INET6_ADDRSTRLEN) +#define HI_UNIX_ADDRSTRLEN \ + (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) + +#define HI_MAXHOSTNAMELEN 256 + +/* + * Length of 1 byte, 2 bytes, 4 bytes, 8 bytes and largest integral + * type (uintmax_t) in ascii, including the null terminator '\0' + * + * From stdint.h, we have: + * # define UINT8_MAX (255) + * # define UINT16_MAX (65535) + * # define UINT32_MAX (4294967295U) + * # define UINT64_MAX (__UINT64_C(18446744073709551615)) + */ +#define HI_UINT8_MAXLEN (3 + 1) +#define HI_UINT16_MAXLEN (5 + 1) +#define HI_UINT32_MAXLEN (10 + 1) +#define HI_UINT64_MAXLEN (20 + 1) +#define HI_UINTMAX_MAXLEN HI_UINT64_MAXLEN + +/* + * Make data 'd' or pointer 'p', n-byte aligned, where n is a power of 2 + * of 2. + */ +#define HI_ALIGNMENT sizeof(unsigned long) /* platform word */ +#define HI_ALIGN(d, n) (((d) + (n - 1)) & ~(n - 1)) +#define HI_ALIGN_PTR(p, n) \ + (void *) (((uintptr_t) (p) + ((uintptr_t) n - 1)) & ~((uintptr_t) n - 1)) + + + +#define str3icmp(m, c0, c1, c2) \ + ((m[0] == c0 || m[0] == (c0 ^ 0x20)) && \ + (m[1] == c1 || m[1] == (c1 ^ 0x20)) && \ + (m[2] == c2 || m[2] == (c2 ^ 0x20))) + +#define str4icmp(m, c0, c1, c2, c3) \ + (str3icmp(m, c0, c1, c2) && (m[3] == c3 || m[3] == (c3 ^ 0x20))) + +#define str5icmp(m, c0, c1, c2, c3, c4) \ + (str4icmp(m, c0, c1, c2, c3) && (m[4] == c4 || m[4] == (c4 ^ 0x20))) + +#define str6icmp(m, c0, c1, c2, c3, c4, c5) \ + (str5icmp(m, c0, c1, c2, c3, c4) && (m[5] == c5 || m[5] == (c5 ^ 0x20))) + +#define str7icmp(m, c0, c1, c2, c3, c4, c5, c6) \ + (str6icmp(m, c0, c1, c2, c3, c4, c5) && \ + (m[6] == c6 || m[6] == (c6 ^ 0x20))) + +#define str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + (str7icmp(m, c0, c1, c2, c3, c4, c5, c6) && \ + (m[7] == c7 || m[7] == (c7 ^ 0x20))) + +#define str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ + (str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \ + (m[8] == c8 || m[8] == (c8 ^ 0x20))) + +#define str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \ + (str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) && \ + (m[9] == c9 || m[9] == (c9 ^ 0x20))) + +#define str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \ + (str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && \ + (m[10] == c10 || m[10] == (c10 ^ 0x20))) + +#define str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \ + (str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) && \ + (m[11] == c11 || m[11] == (c11 ^ 0x20))) + +#define str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) \ + (str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) && \ + (m[12] == c12 || m[12] == (c12 ^ 0x20))) + +#define str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) \ + (str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) && \ + (m[13] == c13 || m[13] == (c13 ^ 0x20))) + +#define str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) \ + (str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) && \ + (m[14] == c14 || m[14] == (c14 ^ 0x20))) + +#define str16icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) \ + (str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) && \ + (m[15] == c15 || m[15] == (c15 ^ 0x20))) + + + +/* + * Wrapper to workaround well known, safe, implicit type conversion when + * invoking system calls. + */ +#define hi_gethostname(_name, _len) \ + gethostname((char *)_name, (size_t)_len) + +#define hi_atoi(_line, _n) \ + _hi_atoi((uint8_t *)_line, (size_t)_n) +#define hi_itoa(_line, _n) \ + _hi_itoa((uint8_t *)_line, (int)_n) + +#define uint_len(_n) \ + _uint_len((uint32_t)_n) + + +int hi_set_blocking(int sd); +int hi_set_nonblocking(int sd); +int hi_set_reuseaddr(int sd); +int hi_set_tcpnodelay(int sd); +int hi_set_linger(int sd, int timeout); +int hi_set_sndbuf(int sd, int size); +int hi_set_rcvbuf(int sd, int size); +int hi_get_soerror(int sd); +int hi_get_sndbuf(int sd); +int hi_get_rcvbuf(int sd); + +int _hi_atoi(uint8_t *line, size_t n); +void _hi_itoa(uint8_t *s, int num); + +int hi_valid_port(int n); + +int _uint_len(uint32_t num); + + +/* + * Memory allocation and free wrappers. + * + * These wrappers enables us to loosely detect double free, dangling + * pointer access and zero-byte alloc. + */ +#define hi_alloc(_s) \ + _hi_alloc((size_t)(_s), __FILE__, __LINE__) + +#define hi_zalloc(_s) \ + _hi_zalloc((size_t)(_s), __FILE__, __LINE__) + +#define hi_calloc(_n, _s) \ + _hi_calloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__) + +#define hi_realloc(_p, _s) \ + _hi_realloc(_p, (size_t)(_s), __FILE__, __LINE__) + +#define hi_free(_p) do { \ + _hi_free(_p, __FILE__, __LINE__); \ + (_p) = NULL; \ +} while (0) + +void *_hi_alloc(size_t size, const char *name, int line); +void *_hi_zalloc(size_t size, const char *name, int line); +void *_hi_calloc(size_t nmemb, size_t size, const char *name, int line); +void *_hi_realloc(void *ptr, size_t size, const char *name, int line); +void _hi_free(void *ptr, const char *name, int line); + + +#define hi_strndup(_s, _n) \ + strndup((char *)(_s), (size_t)(_n)); + +/* + * Wrappers to send or receive n byte message on a blocking + * socket descriptor. + */ +#define hi_sendn(_s, _b, _n) \ + _hi_sendn(_s, _b, (size_t)(_n)) + +#define hi_recvn(_s, _b, _n) \ + _hi_recvn(_s, _b, (size_t)(_n)) + +/* + * Wrappers to read or write data to/from (multiple) buffers + * to a file or socket descriptor. + */ +#define hi_read(_d, _b, _n) \ + read(_d, _b, (size_t)(_n)) + +#define hi_readv(_d, _b, _n) \ + readv(_d, _b, (int)(_n)) + +#define hi_write(_d, _b, _n) \ + write(_d, _b, (size_t)(_n)) + +#define hi_writev(_d, _b, _n) \ + writev(_d, _b, (int)(_n)) + +ssize_t _hi_sendn(int sd, const void *vptr, size_t n); +ssize_t _hi_recvn(int sd, void *vptr, size_t n); + +/* + * Wrappers for defining custom assert based on whether macro + * HI_ASSERT_PANIC or HI_ASSERT_LOG was defined at the moment + * ASSERT was called. + */ +#ifdef HI_ASSERT_PANIC + +#define ASSERT(_x) do { \ + if (!(_x)) { \ + hi_assert(#_x, __FILE__, __LINE__, 1); \ + } \ +} while (0) + +#define NOT_REACHED() ASSERT(0) + +#elif HI_ASSERT_LOG + +#define ASSERT(_x) do { \ + if (!(_x)) { \ + hi_assert(#_x, __FILE__, __LINE__, 0); \ + } \ +} while (0) + +#define NOT_REACHED() ASSERT(0) + +#else + +#define ASSERT(_x) + +#define NOT_REACHED() + +#endif + +void hi_assert(const char *cond, const char *file, int line, int panic); +void hi_stacktrace(int skip_count); +void hi_stacktrace_fd(int fd); + +int _scnprintf(char *buf, size_t size, const char *fmt, ...); +int _vscnprintf(char *buf, size_t size, const char *fmt, va_list args); +int64_t hi_usec_now(void); +int64_t hi_msec_now(void); + +void print_string_with_length(char *s, size_t len); +void print_string_with_length_fix_CRLF(char *s, size_t len); + +uint16_t crc16(const char *buf, int len); + +#endif diff --git a/ext/hiredis-vip-0.3.0/net.c b/ext/hiredis-vip-0.3.0/net.c new file mode 100644 index 00000000..60a2dc75 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/net.c @@ -0,0 +1,458 @@ +/* Extracted from anet.c to work properly with Hiredis error reporting. + * + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net.h" +#include "sds.h" + +/* Defined in hiredis.c */ +void __redisSetError(redisContext *c, int type, const char *str); + +static void redisContextCloseFd(redisContext *c) { + if (c && c->fd >= 0) { + close(c->fd); + c->fd = -1; + } +} + +static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) { + char buf[128] = { 0 }; + size_t len = 0; + + if (prefix != NULL) + len = snprintf(buf,sizeof(buf),"%s: ",prefix); + __redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len); + __redisSetError(c,type,buf); +} + +static int redisSetReuseAddr(redisContext *c) { + int on = 1; + if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + redisContextCloseFd(c); + return REDIS_ERR; + } + return REDIS_OK; +} + +static int redisCreateSocket(redisContext *c, int type) { + int s; + if ((s = socket(type, SOCK_STREAM, 0)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + c->fd = s; + if (type == AF_INET) { + if (redisSetReuseAddr(c) == REDIS_ERR) { + return REDIS_ERR; + } + } + return REDIS_OK; +} + +static int redisSetBlocking(redisContext *c, int blocking) { + int flags; + + /* Set the socket nonblocking. + * Note that fcntl(2) for F_GETFL and F_SETFL can't be + * interrupted by a signal. */ + if ((flags = fcntl(c->fd, F_GETFL)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)"); + redisContextCloseFd(c); + return REDIS_ERR; + } + + if (blocking) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + + if (fcntl(c->fd, F_SETFL, flags) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)"); + redisContextCloseFd(c); + return REDIS_ERR; + } + return REDIS_OK; +} + +int redisKeepAlive(redisContext *c, int interval) { + int val = 1; + int fd = c->fd; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){ + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } + + val = interval; + +#ifdef _OSX + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } +#else +#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) + val = interval; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } + + val = interval/3; + if (val == 0) val = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } + + val = 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { + __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); + return REDIS_ERR; + } +#endif +#endif + + return REDIS_OK; +} + +static int redisSetTcpNoDelay(redisContext *c) { + int yes = 1; + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)"); + redisContextCloseFd(c); + return REDIS_ERR; + } + return REDIS_OK; +} + +#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) + +static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) { + struct pollfd wfd[1]; + long msec; + + msec = -1; + wfd[0].fd = c->fd; + wfd[0].events = POLLOUT; + + /* Only use timeout when not NULL. */ + if (timeout != NULL) { + if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { + __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL); + redisContextCloseFd(c); + return REDIS_ERR; + } + + msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000); + + if (msec < 0 || msec > INT_MAX) { + msec = INT_MAX; + } + } + + if (errno == EINPROGRESS) { + int res; + + if ((res = poll(wfd, 1, msec)) == -1) { + __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)"); + redisContextCloseFd(c); + return REDIS_ERR; + } else if (res == 0) { + errno = ETIMEDOUT; + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + redisContextCloseFd(c); + return REDIS_ERR; + } + + if (redisCheckSocketError(c) != REDIS_OK) + return REDIS_ERR; + + return REDIS_OK; + } + + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + redisContextCloseFd(c); + return REDIS_ERR; +} + +int redisCheckSocketError(redisContext *c) { + int err = 0; + socklen_t errlen = sizeof(err); + + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)"); + return REDIS_ERR; + } + + if (err) { + errno = err; + __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); + return REDIS_ERR; + } + + return REDIS_OK; +} + +int redisContextSetTimeout(redisContext *c, const struct timeval tv) { + if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)"); + return REDIS_ERR; + } + if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) { + __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)"); + return REDIS_ERR; + } + return REDIS_OK; +} + +static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout, + const char *source_addr) { + int s, rv, n; + char _port[6]; /* strlen("65535"); */ + struct addrinfo hints, *servinfo, *bservinfo, *p, *b; + int blocking = (c->flags & REDIS_BLOCK); + int reuseaddr = (c->flags & REDIS_REUSEADDR); + int reuses = 0; + + c->connection_type = REDIS_CONN_TCP; + c->tcp.port = port; + + /* We need to take possession of the passed parameters + * to make them reusable for a reconnect. + * We also carefully check we don't free data we already own, + * as in the case of the reconnect method. + * + * This is a bit ugly, but atleast it works and doesn't leak memory. + **/ + if (c->tcp.host != addr) { + if (c->tcp.host) + free(c->tcp.host); + + c->tcp.host = strdup(addr); + } + + if (timeout) { + if (c->timeout != timeout) { + if (c->timeout == NULL) + c->timeout = malloc(sizeof(struct timeval)); + + memcpy(c->timeout, timeout, sizeof(struct timeval)); + } + } else { + if (c->timeout) + free(c->timeout); + c->timeout = NULL; + } + + if (source_addr == NULL) { + free(c->tcp.source_addr); + c->tcp.source_addr = NULL; + } else if (c->tcp.source_addr != source_addr) { + free(c->tcp.source_addr); + c->tcp.source_addr = strdup(source_addr); + } + + snprintf(_port, 6, "%d", port); + memset(&hints,0,sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + /* Try with IPv6 if no IPv4 address was found. We do it in this order since + * in a Redis client you can't afford to test if you have IPv6 connectivity + * as this would add latency to every connect. Otherwise a more sensible + * route could be: Use IPv6 if both addresses are available and there is IPv6 + * connectivity. */ + if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) { + hints.ai_family = AF_INET6; + if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) { + __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv)); + return REDIS_ERR; + } + } + for (p = servinfo; p != NULL; p = p->ai_next) { +addrretry: + if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1) + continue; + + c->fd = s; + if (redisSetBlocking(c,0) != REDIS_OK) + goto error; + if (c->tcp.source_addr) { + int bound = 0; + /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ + if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) { + char buf[128]; + snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv)); + __redisSetError(c,REDIS_ERR_OTHER,buf); + goto error; + } + + if (reuseaddr) { + n = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n, + sizeof(n)) < 0) { + goto error; + } + } + + for (b = bservinfo; b != NULL; b = b->ai_next) { + if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { + bound = 1; + break; + } + } + freeaddrinfo(bservinfo); + if (!bound) { + char buf[128]; + snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno)); + __redisSetError(c,REDIS_ERR_OTHER,buf); + goto error; + } + } + if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { + if (errno == EHOSTUNREACH) { + redisContextCloseFd(c); + continue; + } else if (errno == EINPROGRESS && !blocking) { + /* This is ok. */ + } else if (errno == EADDRNOTAVAIL && reuseaddr) { + if (++reuses >= REDIS_CONNECT_RETRIES) { + goto error; + } else { + goto addrretry; + } + } else { + if (redisContextWaitReady(c,c->timeout) != REDIS_OK) + goto error; + } + } + if (blocking && redisSetBlocking(c,1) != REDIS_OK) + goto error; + if (redisSetTcpNoDelay(c) != REDIS_OK) + goto error; + + c->flags |= REDIS_CONNECTED; + rv = REDIS_OK; + goto end; + } + if (p == NULL) { + char buf[128]; + snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno)); + __redisSetError(c,REDIS_ERR_OTHER,buf); + goto error; + } + +error: + rv = REDIS_ERR; +end: + freeaddrinfo(servinfo); + return rv; // Need to return REDIS_OK if alright +} + +int redisContextConnectTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout) { + return _redisContextConnectTcp(c, addr, port, timeout, NULL); +} + +int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout, + const char *source_addr) { + return _redisContextConnectTcp(c, addr, port, timeout, source_addr); +} + +int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) { + int blocking = (c->flags & REDIS_BLOCK); + struct sockaddr_un sa; + + if (redisCreateSocket(c,AF_LOCAL) < 0) + return REDIS_ERR; + if (redisSetBlocking(c,0) != REDIS_OK) + return REDIS_ERR; + + c->connection_type = REDIS_CONN_UNIX; + if (c->unix_sock.path != path) + c->unix_sock.path = strdup(path); + + if (timeout) { + if (c->timeout != timeout) { + if (c->timeout == NULL) + c->timeout = malloc(sizeof(struct timeval)); + + memcpy(c->timeout, timeout, sizeof(struct timeval)); + } + } else { + if (c->timeout) + free(c->timeout); + c->timeout = NULL; + } + + sa.sun_family = AF_LOCAL; + strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); + if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { + if (errno == EINPROGRESS && !blocking) { + /* This is ok. */ + } else { + if (redisContextWaitReady(c,c->timeout) != REDIS_OK) + return REDIS_ERR; + } + } + + /* Reset socket to be blocking after connect(2). */ + if (blocking && redisSetBlocking(c,1) != REDIS_OK) + return REDIS_ERR; + + c->flags |= REDIS_CONNECTED; + return REDIS_OK; +} diff --git a/ext/hiredis-vip-0.3.0/net.h b/ext/hiredis-vip-0.3.0/net.h new file mode 100644 index 00000000..2f1a0bf8 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/net.h @@ -0,0 +1,53 @@ +/* Extracted from anet.c to work properly with Hiredis error reporting. + * + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2014, Pieter Noordhuis + * Copyright (c) 2015, Matt Stancliff , + * Jan-Erik Rediger + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __NET_H +#define __NET_H + +#include "hiredis.h" + +#if defined(__sun) +#define AF_LOCAL AF_UNIX +#endif + +int redisCheckSocketError(redisContext *c); +int redisContextSetTimeout(redisContext *c, const struct timeval tv); +int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); +int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, + const struct timeval *timeout, + const char *source_addr); +int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout); +int redisKeepAlive(redisContext *c, int interval); + +#endif diff --git a/ext/hiredis-vip-0.3.0/read.c b/ext/hiredis-vip-0.3.0/read.c new file mode 100644 index 00000000..df1a467a --- /dev/null +++ b/ext/hiredis-vip-0.3.0/read.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fmacros.h" +#include +#include +#ifndef _MSC_VER +#include +#endif +#include +#include +#include + +#include "read.h" +#include "sds.h" + +static void __redisReaderSetError(redisReader *r, int type, const char *str) { + size_t len; + + if (r->reply != NULL && r->fn && r->fn->freeObject) { + r->fn->freeObject(r->reply); + r->reply = NULL; + } + + /* Clear input buffer on errors. */ + if (r->buf != NULL) { + sdsfree(r->buf); + r->buf = NULL; + r->pos = r->len = 0; + } + + /* Reset task stack. */ + r->ridx = -1; + + /* Set error. */ + r->err = type; + len = strlen(str); + len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1); + memcpy(r->errstr,str,len); + r->errstr[len] = '\0'; +} + +static size_t chrtos(char *buf, size_t size, char byte) { + size_t len = 0; + + switch(byte) { + case '\\': + case '"': + len = snprintf(buf,size,"\"\\%c\"",byte); + break; + case '\n': len = snprintf(buf,size,"\"\\n\""); break; + case '\r': len = snprintf(buf,size,"\"\\r\""); break; + case '\t': len = snprintf(buf,size,"\"\\t\""); break; + case '\a': len = snprintf(buf,size,"\"\\a\""); break; + case '\b': len = snprintf(buf,size,"\"\\b\""); break; + default: + if (isprint(byte)) + len = snprintf(buf,size,"\"%c\"",byte); + else + len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte); + break; + } + + return len; +} + +static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) { + char cbuf[8], sbuf[128]; + + chrtos(cbuf,sizeof(cbuf),byte); + snprintf(sbuf,sizeof(sbuf), + "Protocol error, got %s as reply type byte", cbuf); + __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf); +} + +static void __redisReaderSetErrorOOM(redisReader *r) { + __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory"); +} + +static char *readBytes(redisReader *r, unsigned int bytes) { + char *p; + if (r->len-r->pos >= bytes) { + p = r->buf+r->pos; + r->pos += bytes; + return p; + } + return NULL; +} + +/* Find pointer to \r\n. */ +static char *seekNewline(char *s, size_t len) { + int pos = 0; + int _len = len-1; + + /* Position should be < len-1 because the character at "pos" should be + * followed by a \n. Note that strchr cannot be used because it doesn't + * allow to search a limited length and the buffer that is being searched + * might not have a trailing NULL character. */ + while (pos < _len) { + while(pos < _len && s[pos] != '\r') pos++; + if (s[pos] != '\r') { + /* Not found. */ + return NULL; + } else { + if (s[pos+1] == '\n') { + /* Found. */ + return s+pos; + } else { + /* Continue searching. */ + pos++; + } + } + } + return NULL; +} + +/* Read a long long value starting at *s, under the assumption that it will be + * terminated by \r\n. Ambiguously returns -1 for unexpected input. */ +static long long readLongLong(char *s) { + long long v = 0; + int dec, mult = 1; + char c; + + if (*s == '-') { + mult = -1; + s++; + } else if (*s == '+') { + mult = 1; + s++; + } + + while ((c = *(s++)) != '\r') { + dec = c - '0'; + if (dec >= 0 && dec < 10) { + v *= 10; + v += dec; + } else { + /* Should not happen... */ + return -1; + } + } + + return mult*v; +} + +static char *readLine(redisReader *r, int *_len) { + char *p, *s; + int len; + + p = r->buf+r->pos; + s = seekNewline(p,(r->len-r->pos)); + if (s != NULL) { + len = s-(r->buf+r->pos); + r->pos += len+2; /* skip \r\n */ + if (_len) *_len = len; + return p; + } + return NULL; +} + +static void moveToNextTask(redisReader *r) { + redisReadTask *cur, *prv; + while (r->ridx >= 0) { + /* Return a.s.a.p. when the stack is now empty. */ + if (r->ridx == 0) { + r->ridx--; + return; + } + + cur = &(r->rstack[r->ridx]); + prv = &(r->rstack[r->ridx-1]); + assert(prv->type == REDIS_REPLY_ARRAY); + if (cur->idx == prv->elements-1) { + r->ridx--; + } else { + /* Reset the type because the next item can be anything */ + assert(cur->idx < prv->elements); + cur->type = -1; + cur->elements = -1; + cur->idx++; + return; + } + } +} + +static int processLineItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + void *obj; + char *p; + int len; + + if ((p = readLine(r,&len)) != NULL) { + if (cur->type == REDIS_REPLY_INTEGER) { + if (r->fn && r->fn->createInteger) + obj = r->fn->createInteger(cur,readLongLong(p)); + else + obj = (void*)REDIS_REPLY_INTEGER; + } else { + /* Type will be error or status. */ + if (r->fn && r->fn->createString) + obj = r->fn->createString(cur,p,len); + else + obj = (void*)(size_t)(cur->type); + } + + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + /* Set reply if this is the root object. */ + if (r->ridx == 0) r->reply = obj; + moveToNextTask(r); + return REDIS_OK; + } + + return REDIS_ERR; +} + +static int processBulkItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + void *obj = NULL; + char *p, *s; + long len; + unsigned long bytelen; + int success = 0; + + p = r->buf+r->pos; + s = seekNewline(p,r->len-r->pos); + if (s != NULL) { + p = r->buf+r->pos; + bytelen = s-(r->buf+r->pos)+2; /* include \r\n */ + len = readLongLong(p); + + if (len < 0) { + /* The nil object can always be created. */ + if (r->fn && r->fn->createNil) + obj = r->fn->createNil(cur); + else + obj = (void*)REDIS_REPLY_NIL; + success = 1; + } else { + /* Only continue when the buffer contains the entire bulk item. */ + bytelen += len+2; /* include \r\n */ + if (r->pos+bytelen <= r->len) { + if (r->fn && r->fn->createString) + obj = r->fn->createString(cur,s+2,len); + else + obj = (void*)REDIS_REPLY_STRING; + success = 1; + } + } + + /* Proceed when obj was created. */ + if (success) { + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + r->pos += bytelen; + + /* Set reply if this is the root object. */ + if (r->ridx == 0) r->reply = obj; + moveToNextTask(r); + return REDIS_OK; + } + } + + return REDIS_ERR; +} + +static int processMultiBulkItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + void *obj; + char *p; + long elements; + int root = 0; + + /* Set error for nested multi bulks with depth > 7 */ + if (r->ridx == 8) { + __redisReaderSetError(r,REDIS_ERR_PROTOCOL, + "No support for nested multi bulk replies with depth > 7"); + return REDIS_ERR; + } + + if ((p = readLine(r,NULL)) != NULL) { + elements = readLongLong(p); + root = (r->ridx == 0); + + if (elements == -1) { + if (r->fn && r->fn->createNil) + obj = r->fn->createNil(cur); + else + obj = (void*)REDIS_REPLY_NIL; + + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + moveToNextTask(r); + } else { + if (r->fn && r->fn->createArray) + obj = r->fn->createArray(cur,elements); + else + obj = (void*)REDIS_REPLY_ARRAY; + + if (obj == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + /* Modify task stack when there are more than 0 elements. */ + if (elements > 0) { + cur->elements = elements; + cur->obj = obj; + r->ridx++; + r->rstack[r->ridx].type = -1; + r->rstack[r->ridx].elements = -1; + r->rstack[r->ridx].idx = 0; + r->rstack[r->ridx].obj = NULL; + r->rstack[r->ridx].parent = cur; + r->rstack[r->ridx].privdata = r->privdata; + } else { + moveToNextTask(r); + } + } + + /* Set reply if this is the root object. */ + if (root) r->reply = obj; + return REDIS_OK; + } + + return REDIS_ERR; +} + +static int processItem(redisReader *r) { + redisReadTask *cur = &(r->rstack[r->ridx]); + char *p; + + /* check if we need to read type */ + if (cur->type < 0) { + if ((p = readBytes(r,1)) != NULL) { + switch (p[0]) { + case '-': + cur->type = REDIS_REPLY_ERROR; + break; + case '+': + cur->type = REDIS_REPLY_STATUS; + break; + case ':': + cur->type = REDIS_REPLY_INTEGER; + break; + case '$': + cur->type = REDIS_REPLY_STRING; + break; + case '*': + cur->type = REDIS_REPLY_ARRAY; + break; + default: + __redisReaderSetErrorProtocolByte(r,*p); + return REDIS_ERR; + } + } else { + /* could not consume 1 byte */ + return REDIS_ERR; + } + } + + /* process typed item */ + switch(cur->type) { + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_INTEGER: + return processLineItem(r); + case REDIS_REPLY_STRING: + return processBulkItem(r); + case REDIS_REPLY_ARRAY: + return processMultiBulkItem(r); + default: + assert(NULL); + return REDIS_ERR; /* Avoid warning. */ + } +} + +redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { + redisReader *r; + + r = calloc(sizeof(redisReader),1); + if (r == NULL) + return NULL; + + r->err = 0; + r->errstr[0] = '\0'; + r->fn = fn; + r->buf = sdsempty(); + r->maxbuf = REDIS_READER_MAX_BUF; + if (r->buf == NULL) { + free(r); + return NULL; + } + + r->ridx = -1; + return r; +} + +void redisReaderFree(redisReader *r) { + if (r->reply != NULL && r->fn && r->fn->freeObject) + r->fn->freeObject(r->reply); + if (r->buf != NULL) + sdsfree(r->buf); + free(r); +} + +int redisReaderFeed(redisReader *r, const char *buf, size_t len) { + sds newbuf; + + /* Return early when this reader is in an erroneous state. */ + if (r->err) + return REDIS_ERR; + + /* Copy the provided buffer. */ + if (buf != NULL && len >= 1) { + /* Destroy internal buffer when it is empty and is quite large. */ + if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) { + sdsfree(r->buf); + r->buf = sdsempty(); + r->pos = 0; + + /* r->buf should not be NULL since we just free'd a larger one. */ + assert(r->buf != NULL); + } + + newbuf = sdscatlen(r->buf,buf,len); + if (newbuf == NULL) { + __redisReaderSetErrorOOM(r); + return REDIS_ERR; + } + + r->buf = newbuf; + r->len = sdslen(r->buf); + } + + return REDIS_OK; +} + +int redisReaderGetReply(redisReader *r, void **reply) { + /* Default target pointer to NULL. */ + if (reply != NULL) + *reply = NULL; + + /* Return early when this reader is in an erroneous state. */ + if (r->err) + return REDIS_ERR; + + /* When the buffer is empty, there will never be a reply. */ + if (r->len == 0) + return REDIS_OK; + + /* Set first item to process when the stack is empty. */ + if (r->ridx == -1) { + r->rstack[0].type = -1; + r->rstack[0].elements = -1; + r->rstack[0].idx = -1; + r->rstack[0].obj = NULL; + r->rstack[0].parent = NULL; + r->rstack[0].privdata = r->privdata; + r->ridx = 0; + } + + /* Process items in reply. */ + while (r->ridx >= 0) + if (processItem(r) != REDIS_OK) + break; + + /* Return ASAP when an error occurred. */ + if (r->err) + return REDIS_ERR; + + /* Discard part of the buffer when we've consumed at least 1k, to avoid + * doing unnecessary calls to memmove() in sds.c. */ + if (r->pos >= 1024) { + sdsrange(r->buf,r->pos,-1); + r->pos = 0; + r->len = sdslen(r->buf); + } + + /* Emit a reply when there is one. */ + if (r->ridx == -1) { + if (reply != NULL) + *reply = r->reply; + r->reply = NULL; + } + return REDIS_OK; +} diff --git a/ext/hiredis-vip-0.3.0/read.h b/ext/hiredis-vip-0.3.0/read.h new file mode 100644 index 00000000..088c9790 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/read.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2009-2011, Salvatore Sanfilippo + * Copyright (c) 2010-2011, Pieter Noordhuis + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __HIREDIS_READ_H +#define __HIREDIS_READ_H +#include /* for size_t */ + +#define REDIS_ERR -1 +#define REDIS_OK 0 + +/* When an error occurs, the err flag in a context is set to hold the type of + * error that occured. REDIS_ERR_IO means there was an I/O error and you + * should use the "errno" variable to find out what is wrong. + * For other values, the "errstr" field will hold a description. */ +#define REDIS_ERR_IO 1 /* Error in read or write */ +#define REDIS_ERR_EOF 3 /* End of file */ +#define REDIS_ERR_PROTOCOL 4 /* Protocol error */ +#define REDIS_ERR_OOM 5 /* Out of memory */ +#define REDIS_ERR_OTHER 2 /* Everything else... */ +#if 1 //shenzheng 2015-8-10 redis cluster +#define REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT 6 +#endif //shenzheng 2015-8-10 redis cluster + +#define REDIS_REPLY_STRING 1 +#define REDIS_REPLY_ARRAY 2 +#define REDIS_REPLY_INTEGER 3 +#define REDIS_REPLY_NIL 4 +#define REDIS_REPLY_STATUS 5 +#define REDIS_REPLY_ERROR 6 + +#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */ + +#if 1 //shenzheng 2015-8-22 redis cluster +#define REDIS_ERROR_MOVED "MOVED" +#define REDIS_ERROR_ASK "ASK" +#define REDIS_ERROR_TRYAGAIN "TRYAGAIN" +#define REDIS_ERROR_CROSSSLOT "CROSSSLOT" +#define REDIS_ERROR_CLUSTERDOWN "CLUSTERDOWN" + +#define REDIS_STATUS_OK "OK" +#endif //shenzheng 2015-9-24 redis cluster + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct redisReadTask { + int type; + int elements; /* number of elements in multibulk container */ + int idx; /* index in parent (array) object */ + void *obj; /* holds user-generated value for a read task */ + struct redisReadTask *parent; /* parent task */ + void *privdata; /* user-settable arbitrary field */ +} redisReadTask; + +typedef struct redisReplyObjectFunctions { + void *(*createString)(const redisReadTask*, char*, size_t); + void *(*createArray)(const redisReadTask*, int); + void *(*createInteger)(const redisReadTask*, long long); + void *(*createNil)(const redisReadTask*); + void (*freeObject)(void*); +} redisReplyObjectFunctions; + +typedef struct redisReader { + int err; /* Error flags, 0 when there is no error */ + char errstr[128]; /* String representation of error when applicable */ + + char *buf; /* Read buffer */ + size_t pos; /* Buffer cursor */ + size_t len; /* Buffer length */ + size_t maxbuf; /* Max length of unused buffer */ + + redisReadTask rstack[9]; + int ridx; /* Index of current read task */ + void *reply; /* Temporary reply pointer */ + + redisReplyObjectFunctions *fn; + void *privdata; +} redisReader; + +/* Public API for the protocol parser. */ +redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); +void redisReaderFree(redisReader *r); +int redisReaderFeed(redisReader *r, const char *buf, size_t len); +int redisReaderGetReply(redisReader *r, void **reply); + +/* Backwards compatibility, can be removed on big version bump. */ +#define redisReplyReaderCreate redisReaderCreate +#define redisReplyReaderFree redisReaderFree +#define redisReplyReaderFeed redisReaderFeed +#define redisReplyReaderGetReply redisReaderGetReply +#define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) +#define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply) +#define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/hiredis-vip-0.3.0/sds.c b/ext/hiredis-vip-0.3.0/sds.c new file mode 100644 index 00000000..5d55b779 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/sds.c @@ -0,0 +1,1095 @@ +/* SDS (Simple Dynamic Strings), A C dynamic strings library. + * + * Copyright (c) 2006-2014, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "sds.h" + +/* Create a new sds string with the content specified by the 'init' pointer + * and 'initlen'. + * If NULL is used for 'init' the string is initialized with zero bytes. + * + * The string is always null-termined (all the sds strings are, always) so + * even if you create an sds string with: + * + * mystring = sdsnewlen("abc",3"); + * + * You can print the string with printf() as there is an implicit \0 at the + * end of the string. However the string is binary safe and can contain + * \0 characters in the middle, as the length is stored in the sds header. */ +sds sdsnewlen(const void *init, size_t initlen) { + struct sdshdr *sh; + + if (init) { + sh = malloc(sizeof *sh+initlen+1); + } else { + sh = calloc(sizeof *sh+initlen+1,1); + } + if (sh == NULL) return NULL; + sh->len = initlen; + sh->free = 0; + if (initlen && init) + memcpy(sh->buf, init, initlen); + sh->buf[initlen] = '\0'; + return (char*)sh->buf; +} + +/* Create an empty (zero length) sds string. Even in this case the string + * always has an implicit null term. */ +sds sdsempty(void) { + return sdsnewlen("",0); +} + +/* Create a new sds string starting from a null termined C string. */ +sds sdsnew(const char *init) { + size_t initlen = (init == NULL) ? 0 : strlen(init); + return sdsnewlen(init, initlen); +} + +/* Duplicate an sds string. */ +sds sdsdup(const sds s) { + return sdsnewlen(s, sdslen(s)); +} + +/* Free an sds string. No operation is performed if 's' is NULL. */ +void sdsfree(sds s) { + if (s == NULL) return; + free(s-sizeof(struct sdshdr)); +} + +/* Set the sds string length to the length as obtained with strlen(), so + * considering as content only up to the first null term character. + * + * This function is useful when the sds string is hacked manually in some + * way, like in the following example: + * + * s = sdsnew("foobar"); + * s[2] = '\0'; + * sdsupdatelen(s); + * printf("%d\n", sdslen(s)); + * + * The output will be "2", but if we comment out the call to sdsupdatelen() + * the output will be "6" as the string was modified but the logical length + * remains 6 bytes. */ +void sdsupdatelen(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + int reallen = strlen(s); + sh->free += (sh->len-reallen); + sh->len = reallen; +} + +/* Modify an sds string on-place to make it empty (zero length). + * However all the existing buffer is not discarded but set as free space + * so that next append operations will not require allocations up to the + * number of bytes previously available. */ +void sdsclear(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + sh->free += sh->len; + sh->len = 0; + sh->buf[0] = '\0'; +} + +/* Enlarge the free space at the end of the sds string so that the caller + * is sure that after calling this function can overwrite up to addlen + * bytes after the end of the string, plus one more byte for nul term. + * + * Note: this does not change the *length* of the sds string as returned + * by sdslen(), but only the free buffer space we have. */ +sds sdsMakeRoomFor(sds s, size_t addlen) { + struct sdshdr *sh, *newsh; + size_t free = sdsavail(s); + size_t len, newlen; + + if (free >= addlen) return s; + len = sdslen(s); + sh = (void*) (s-sizeof *sh); + newlen = (len+addlen); + if (newlen < SDS_MAX_PREALLOC) + newlen *= 2; + else + newlen += SDS_MAX_PREALLOC; + newsh = realloc(sh, sizeof *newsh+newlen+1); + if (newsh == NULL) return NULL; + + newsh->free = newlen - len; + return newsh->buf; +} + +/* Reallocate the sds string so that it has no free space at the end. The + * contained string remains not altered, but next concatenation operations + * will require a reallocation. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdsRemoveFreeSpace(sds s) { + struct sdshdr *sh; + + sh = (void*) (s-sizeof *sh); + sh = realloc(sh, sizeof *sh+sh->len+1); + sh->free = 0; + return sh->buf; +} + +/* Return the total size of the allocation of the specifed sds string, + * including: + * 1) The sds header before the pointer. + * 2) The string. + * 3) The free buffer at the end if any. + * 4) The implicit null term. + */ +size_t sdsAllocSize(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + + return sizeof(*sh)+sh->len+sh->free+1; +} + +/* Increment the sds length and decrements the left free space at the + * end of the string according to 'incr'. Also set the null term + * in the new end of the string. + * + * This function is used in order to fix the string length after the + * user calls sdsMakeRoomFor(), writes something after the end of + * the current string, and finally needs to set the new length. + * + * Note: it is possible to use a negative increment in order to + * right-trim the string. + * + * Usage example: + * + * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the + * following schema, to cat bytes coming from the kernel to the end of an + * sds string without copying into an intermediate buffer: + * + * oldlen = sdslen(s); + * s = sdsMakeRoomFor(s, BUFFER_SIZE); + * nread = read(fd, s+oldlen, BUFFER_SIZE); + * ... check for nread <= 0 and handle it ... + * sdsIncrLen(s, nread); + */ +void sdsIncrLen(sds s, int incr) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + + assert(sh->free >= incr); + sh->len += incr; + sh->free -= incr; + assert(sh->free >= 0); + s[sh->len] = '\0'; +} + +/* Grow the sds to have the specified length. Bytes that were not part of + * the original length of the sds will be set to zero. + * + * if the specified length is smaller than the current length, no operation + * is performed. */ +sds sdsgrowzero(sds s, size_t len) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t totlen, curlen = sh->len; + + if (len <= curlen) return s; + s = sdsMakeRoomFor(s,len-curlen); + if (s == NULL) return NULL; + + /* Make sure added region doesn't contain garbage */ + sh = (void*)(s-sizeof *sh); + memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ + totlen = sh->len+sh->free; + sh->len = len; + sh->free = totlen-sh->len; + return s; +} + +/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the + * end of the specified sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatlen(sds s, const void *t, size_t len) { + struct sdshdr *sh; + size_t curlen = sdslen(s); + + s = sdsMakeRoomFor(s,len); + if (s == NULL) return NULL; + sh = (void*) (s-sizeof *sh); + memcpy(s+curlen, t, len); + sh->len = curlen+len; + sh->free = sh->free-len; + s[curlen+len] = '\0'; + return s; +} + +/* Append the specified null termianted C string to the sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscat(sds s, const char *t) { + return sdscatlen(s, t, strlen(t)); +} + +/* Append the specified sds 't' to the existing sds 's'. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatsds(sds s, const sds t) { + return sdscatlen(s, t, sdslen(t)); +} + +/* Destructively modify the sds string 's' to hold the specified binary + * safe string pointed by 't' of length 'len' bytes. */ +sds sdscpylen(sds s, const char *t, size_t len) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t totlen = sh->free+sh->len; + + if (totlen < len) { + s = sdsMakeRoomFor(s,len-sh->len); + if (s == NULL) return NULL; + sh = (void*) (s-sizeof *sh); + totlen = sh->free+sh->len; + } + memcpy(s, t, len); + s[len] = '\0'; + sh->len = len; + sh->free = totlen-len; + return s; +} + +/* Like sdscpylen() but 't' must be a null-termined string so that the length + * of the string is obtained with strlen(). */ +sds sdscpy(sds s, const char *t) { + return sdscpylen(s, t, strlen(t)); +} + +/* Helper for sdscatlonglong() doing the actual number -> string + * conversion. 's' must point to a string with room for at least + * SDS_LLSTR_SIZE bytes. + * + * The function returns the lenght of the null-terminated string + * representation stored at 's'. */ +#define SDS_LLSTR_SIZE 21 +int sdsll2str(char *s, long long value) { + char *p, aux; + unsigned long long v; + size_t l; + + /* Generate the string representation, this method produces + * an reversed string. */ + v = (value < 0) ? -value : value; + p = s; + do { + *p++ = '0'+(v%10); + v /= 10; + } while(v); + if (value < 0) *p++ = '-'; + + /* Compute length and add null term. */ + l = p-s; + *p = '\0'; + + /* Reverse the string. */ + p--; + while(s < p) { + aux = *s; + *s = *p; + *p = aux; + s++; + p--; + } + return l; +} + +/* Identical sdsll2str(), but for unsigned long long type. */ +int sdsull2str(char *s, unsigned long long v) { + char *p, aux; + size_t l; + + /* Generate the string representation, this method produces + * an reversed string. */ + p = s; + do { + *p++ = '0'+(v%10); + v /= 10; + } while(v); + + /* Compute length and add null term. */ + l = p-s; + *p = '\0'; + + /* Reverse the string. */ + p--; + while(s < p) { + aux = *s; + *s = *p; + *p = aux; + s++; + p--; + } + return l; +} + +/* Like sdscatpritf() but gets va_list instead of being variadic. */ +sds sdscatvprintf(sds s, const char *fmt, va_list ap) { + va_list cpy; + char *buf, *t; + size_t buflen = 16; + + while(1) { + buf = malloc(buflen); + if (buf == NULL) return NULL; + buf[buflen-2] = '\0'; + va_copy(cpy,ap); + vsnprintf(buf, buflen, fmt, cpy); + if (buf[buflen-2] != '\0') { + free(buf); + buflen *= 2; + continue; + } + break; + } + t = sdscat(s, buf); + free(buf); + return t; +} + +/* Append to the sds string 's' a string obtained using printf-alike format + * specifier. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. + * + * Example: + * + * s = sdsnew("Sum is: "); + * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b); + * + * Often you need to create a string from scratch with the printf-alike + * format. When this is the need, just use sdsempty() as the target string: + * + * s = sdscatprintf(sdsempty(), "... your format ...", args); + */ +sds sdscatprintf(sds s, const char *fmt, ...) { + va_list ap; + char *t; + va_start(ap, fmt); + t = sdscatvprintf(s,fmt,ap); + va_end(ap); + return t; +} + +/* This function is similar to sdscatprintf, but much faster as it does + * not rely on sprintf() family functions implemented by the libc that + * are often very slow. Moreover directly handling the sds string as + * new data is concatenated provides a performance improvement. + * + * However this function only handles an incompatible subset of printf-alike + * format specifiers: + * + * %s - C String + * %S - SDS string + * %i - signed int + * %I - 64 bit signed integer (long long, int64_t) + * %u - unsigned int + * %U - 64 bit unsigned integer (unsigned long long, uint64_t) + * %T - A size_t variable. + * %% - Verbatim "%" character. + */ +sds sdscatfmt(sds s, char const *fmt, ...) { + struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); + size_t initlen = sdslen(s); + const char *f = fmt; + int i; + va_list ap; + + va_start(ap,fmt); + f = fmt; /* Next format specifier byte to process. */ + i = initlen; /* Position of the next byte to write to dest str. */ + while(*f) { + char next, *str; + int l; + long long num; + unsigned long long unum; + + /* Make sure there is always space for at least 1 char. */ + if (sh->free == 0) { + s = sdsMakeRoomFor(s,1); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + + switch(*f) { + case '%': + next = *(f+1); + f++; + switch(next) { + case 's': + case 'S': + str = va_arg(ap,char*); + l = (next == 's') ? strlen(str) : sdslen(str); + if (sh->free < l) { + s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + memcpy(s+i,str,l); + sh->len += l; + sh->free -= l; + i += l; + break; + case 'i': + case 'I': + if (next == 'i') + num = va_arg(ap,int); + else + num = va_arg(ap,long long); + { + char buf[SDS_LLSTR_SIZE]; + l = sdsll2str(buf,num); + if (sh->free < l) { + s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + memcpy(s+i,buf,l); + sh->len += l; + sh->free -= l; + i += l; + } + break; + case 'u': + case 'U': + case 'T': + if (next == 'u') + unum = va_arg(ap,unsigned int); + else if(next == 'U') + unum = va_arg(ap,unsigned long long); + else + unum = (unsigned long long)va_arg(ap,size_t); + { + char buf[SDS_LLSTR_SIZE]; + l = sdsull2str(buf,unum); + if (sh->free < l) { + s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); + } + memcpy(s+i,buf,l); + sh->len += l; + sh->free -= l; + i += l; + } + break; + default: /* Handle %% and generally %. */ + s[i++] = next; + sh->len += 1; + sh->free -= 1; + break; + } + break; + default: + s[i++] = *f; + sh->len += 1; + sh->free -= 1; + break; + } + f++; + } + va_end(ap); + + /* Add null-term */ + s[i] = '\0'; + return s; +} + + +/* Remove the part of the string from left and from right composed just of + * contiguous characters found in 'cset', that is a null terminted C string. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. + * + * Example: + * + * s = sdsnew("AA...AA.a.aa.aHelloWorld :::"); + * s = sdstrim(s,"A. :"); + * printf("%s\n", s); + * + * Output will be just "Hello World". + */ +void sdstrim(sds s, const char *cset) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + char *start, *end, *sp, *ep; + size_t len; + + sp = start = s; + ep = end = s+sdslen(s)-1; + while(sp <= end && strchr(cset, *sp)) sp++; + while(ep > start && strchr(cset, *ep)) ep--; + len = (sp > ep) ? 0 : ((ep-sp)+1); + if (sh->buf != sp) memmove(sh->buf, sp, len); + sh->buf[len] = '\0'; + sh->free = sh->free+(sh->len-len); + sh->len = len; +} + +/* Turn the string into a smaller (or equal) string containing only the + * substring specified by the 'start' and 'end' indexes. + * + * start and end can be negative, where -1 means the last character of the + * string, -2 the penultimate character, and so forth. + * + * The interval is inclusive, so the start and end characters will be part + * of the resulting string. + * + * The string is modified in-place. + * + * Example: + * + * s = sdsnew("Hello World"); + * sdsrange(s,1,-1); => "ello World" + */ +void sdsrange(sds s, int start, int end) { + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t newlen, len = sdslen(s); + + if (len == 0) return; + if (start < 0) { + start = len+start; + if (start < 0) start = 0; + } + if (end < 0) { + end = len+end; + if (end < 0) end = 0; + } + newlen = (start > end) ? 0 : (end-start)+1; + if (newlen != 0) { + if (start >= (signed)len) { + newlen = 0; + } else if (end >= (signed)len) { + end = len-1; + newlen = (start > end) ? 0 : (end-start)+1; + } + } else { + start = 0; + } + if (start && newlen) memmove(sh->buf, sh->buf+start, newlen); + sh->buf[newlen] = 0; + sh->free = sh->free+(sh->len-newlen); + sh->len = newlen; +} + +/* Apply tolower() to every character of the sds string 's'. */ +void sdstolower(sds s) { + int len = sdslen(s), j; + + for (j = 0; j < len; j++) s[j] = tolower(s[j]); +} + +/* Apply toupper() to every character of the sds string 's'. */ +void sdstoupper(sds s) { + int len = sdslen(s), j; + + for (j = 0; j < len; j++) s[j] = toupper(s[j]); +} + +/* Compare two sds strings s1 and s2 with memcmp(). + * + * Return value: + * + * 1 if s1 > s2. + * -1 if s1 < s2. + * 0 if s1 and s2 are exactly the same binary string. + * + * If two strings share exactly the same prefix, but one of the two has + * additional characters, the longer string is considered to be greater than + * the smaller one. */ +int sdscmp(const sds s1, const sds s2) { + size_t l1, l2, minlen; + int cmp; + + l1 = sdslen(s1); + l2 = sdslen(s2); + minlen = (l1 < l2) ? l1 : l2; + cmp = memcmp(s1,s2,minlen); + if (cmp == 0) return l1-l2; + return cmp; +} + +/* Split 's' with separator in 'sep'. An array + * of sds strings is returned. *count will be set + * by reference to the number of tokens returned. + * + * On out of memory, zero length string, zero length + * separator, NULL is returned. + * + * Note that 'sep' is able to split a string using + * a multi-character separator. For example + * sdssplit("foo_-_bar","_-_"); will return two + * elements "foo" and "bar". + * + * This version of the function is binary-safe but + * requires length arguments. sdssplit() is just the + * same function but for zero-terminated strings. + */ +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) { + int elements = 0, slots = 5, start = 0, j; + sds *tokens; + + if (seplen < 1 || len < 0) return NULL; + + tokens = malloc(sizeof(sds)*slots); + if (tokens == NULL) return NULL; + + if (len == 0) { + *count = 0; + return tokens; + } + for (j = 0; j < (len-(seplen-1)); j++) { + /* make sure there is room for the next element and the final one */ + if (slots < elements+2) { + sds *newtokens; + + slots *= 2; + newtokens = realloc(tokens,sizeof(sds)*slots); + if (newtokens == NULL) goto cleanup; + tokens = newtokens; + } + /* search the separator */ + if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) { + tokens[elements] = sdsnewlen(s+start,j-start); + if (tokens[elements] == NULL) goto cleanup; + elements++; + start = j+seplen; + j = j+seplen-1; /* skip the separator */ + } + } + /* Add the final element. We are sure there is room in the tokens array. */ + tokens[elements] = sdsnewlen(s+start,len-start); + if (tokens[elements] == NULL) goto cleanup; + elements++; + *count = elements; + return tokens; + +cleanup: + { + int i; + for (i = 0; i < elements; i++) sdsfree(tokens[i]); + free(tokens); + *count = 0; + return NULL; + } +} + +/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */ +void sdsfreesplitres(sds *tokens, int count) { + if (!tokens) return; + while(count--) + sdsfree(tokens[count]); + free(tokens); +} + +/* Create an sds string from a long long value. It is much faster than: + * + * sdscatprintf(sdsempty(),"%lld\n", value); + */ +sds sdsfromlonglong(long long value) { + char buf[32], *p; + unsigned long long v; + + v = (value < 0) ? -value : value; + p = buf+31; /* point to the last character */ + do { + *p-- = '0'+(v%10); + v /= 10; + } while(v); + if (value < 0) *p-- = '-'; + p++; + return sdsnewlen(p,32-(p-buf)); +} + +/* Append to the sds string "s" an escaped string representation where + * all the non-printable characters (tested with isprint()) are turned into + * escapes in the form "\n\r\a...." or "\x". + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatrepr(sds s, const char *p, size_t len) { + s = sdscatlen(s,"\"",1); + while(len--) { + switch(*p) { + case '\\': + case '"': + s = sdscatprintf(s,"\\%c",*p); + break; + case '\n': s = sdscatlen(s,"\\n",2); break; + case '\r': s = sdscatlen(s,"\\r",2); break; + case '\t': s = sdscatlen(s,"\\t",2); break; + case '\a': s = sdscatlen(s,"\\a",2); break; + case '\b': s = sdscatlen(s,"\\b",2); break; + default: + if (isprint(*p)) + s = sdscatprintf(s,"%c",*p); + else + s = sdscatprintf(s,"\\x%02x",(unsigned char)*p); + break; + } + p++; + } + return sdscatlen(s,"\"",1); +} + +/* Helper function for sdssplitargs() that returns non zero if 'c' + * is a valid hex digit. */ +int is_hex_digit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +/* Helper function for sdssplitargs() that converts a hex digit into an + * integer from 0 to 15 */ +int hex_digit_to_int(char c) { + switch(c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': case 'A': return 10; + case 'b': case 'B': return 11; + case 'c': case 'C': return 12; + case 'd': case 'D': return 13; + case 'e': case 'E': return 14; + case 'f': case 'F': return 15; + default: return 0; + } +} + +/* Split a line into arguments, where every argument can be in the + * following programming-language REPL-alike form: + * + * foo bar "newline are supported\n" and "\xff\x00otherstuff" + * + * The number of arguments is stored into *argc, and an array + * of sds is returned. + * + * The caller should free the resulting array of sds strings with + * sdsfreesplitres(). + * + * Note that sdscatrepr() is able to convert back a string into + * a quoted string in the same format sdssplitargs() is able to parse. + * + * The function returns the allocated tokens on success, even when the + * input string is empty, or NULL if the input contains unbalanced + * quotes or closed quotes followed by non space characters + * as in: "foo"bar or "foo' + */ +sds *sdssplitargs(const char *line, int *argc) { + const char *p = line; + char *current = NULL; + char **vector = NULL; + + *argc = 0; + while(1) { + /* skip blanks */ + while(*p && isspace(*p)) p++; + if (*p) { + /* get a token */ + int inq=0; /* set to 1 if we are in "quotes" */ + int insq=0; /* set to 1 if we are in 'single quotes' */ + int done=0; + + if (current == NULL) current = sdsempty(); + while(!done) { + if (inq) { + if (*p == '\\' && *(p+1) == 'x' && + is_hex_digit(*(p+2)) && + is_hex_digit(*(p+3))) + { + unsigned char byte; + + byte = (hex_digit_to_int(*(p+2))*16)+ + hex_digit_to_int(*(p+3)); + current = sdscatlen(current,(char*)&byte,1); + p += 3; + } else if (*p == '\\' && *(p+1)) { + char c; + + p++; + switch(*p) { + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'b': c = '\b'; break; + case 'a': c = '\a'; break; + default: c = *p; break; + } + current = sdscatlen(current,&c,1); + } else if (*p == '"') { + /* closing quote must be followed by a space or + * nothing at all. */ + if (*(p+1) && !isspace(*(p+1))) goto err; + done=1; + } else if (!*p) { + /* unterminated quotes */ + goto err; + } else { + current = sdscatlen(current,p,1); + } + } else if (insq) { + if (*p == '\\' && *(p+1) == '\'') { + p++; + current = sdscatlen(current,"'",1); + } else if (*p == '\'') { + /* closing quote must be followed by a space or + * nothing at all. */ + if (*(p+1) && !isspace(*(p+1))) goto err; + done=1; + } else if (!*p) { + /* unterminated quotes */ + goto err; + } else { + current = sdscatlen(current,p,1); + } + } else { + switch(*p) { + case ' ': + case '\n': + case '\r': + case '\t': + case '\0': + done=1; + break; + case '"': + inq=1; + break; + case '\'': + insq=1; + break; + default: + current = sdscatlen(current,p,1); + break; + } + } + if (*p) p++; + } + /* add the token to the vector */ + vector = realloc(vector,((*argc)+1)*sizeof(char*)); + vector[*argc] = current; + (*argc)++; + current = NULL; + } else { + /* Even on empty input string return something not NULL. */ + if (vector == NULL) vector = malloc(sizeof(void*)); + return vector; + } + } + +err: + while((*argc)--) + sdsfree(vector[*argc]); + free(vector); + if (current) sdsfree(current); + *argc = 0; + return NULL; +} + +/* Modify the string substituting all the occurrences of the set of + * characters specified in the 'from' string to the corresponding character + * in the 'to' array. + * + * For instance: sdsmapchars(mystring, "ho", "01", 2) + * will have the effect of turning the string "hello" into "0ell1". + * + * The function returns the sds string pointer, that is always the same + * as the input pointer since no resize is needed. */ +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) { + size_t j, i, l = sdslen(s); + + for (j = 0; j < l; j++) { + for (i = 0; i < setlen; i++) { + if (s[j] == from[i]) { + s[j] = to[i]; + break; + } + } + } + return s; +} + +/* Join an array of C strings using the specified separator (also a C string). + * Returns the result as an sds string. */ +sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) { + sds join = sdsempty(); + int j; + + for (j = 0; j < argc; j++) { + join = sdscat(join, argv[j]); + if (j != argc-1) join = sdscatlen(join,sep,seplen); + } + return join; +} + +/* Like sdsjoin, but joins an array of SDS strings. */ +sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) { + sds join = sdsempty(); + int j; + + for (j = 0; j < argc; j++) { + join = sdscatsds(join, argv[j]); + if (j != argc-1) join = sdscatlen(join,sep,seplen); + } + return join; +} + +#ifdef SDS_TEST_MAIN +#include +#include "testhelp.h" + +int main(void) { + { + struct sdshdr *sh; + sds x = sdsnew("foo"), y; + + test_cond("Create a string and obtain the length", + sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) + + sdsfree(x); + x = sdsnewlen("foo",2); + test_cond("Create a string with specified length", + sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) + + x = sdscat(x,"bar"); + test_cond("Strings concatenation", + sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); + + x = sdscpy(x,"a"); + test_cond("sdscpy() against an originally longer string", + sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) + + x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); + test_cond("sdscpy() against an originally shorter string", + sdslen(x) == 33 && + memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) + + sdsfree(x); + x = sdscatprintf(sdsempty(),"%d",123); + test_cond("sdscatprintf() seems working in the base case", + sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) + + sdsfree(x); + x = sdsnew("xxciaoyyy"); + sdstrim(x,"xy"); + test_cond("sdstrim() correctly trims characters", + sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) + + y = sdsdup(x); + sdsrange(y,1,1); + test_cond("sdsrange(...,1,1)", + sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,1,-1); + test_cond("sdsrange(...,1,-1)", + sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,-2,-1); + test_cond("sdsrange(...,-2,-1)", + sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,2,1); + test_cond("sdsrange(...,2,1)", + sdslen(y) == 0 && memcmp(y,"\0",1) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,1,100); + test_cond("sdsrange(...,1,100)", + sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) + + sdsfree(y); + y = sdsdup(x); + sdsrange(y,100,100); + test_cond("sdsrange(...,100,100)", + sdslen(y) == 0 && memcmp(y,"\0",1) == 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("foo"); + y = sdsnew("foa"); + test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("bar"); + y = sdsnew("bar"); + test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("aar"); + y = sdsnew("bar"); + test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) + + sdsfree(y); + sdsfree(x); + x = sdsnewlen("\a\n\0foo\r",7); + y = sdscatrepr(sdsempty(),x,sdslen(x)); + test_cond("sdscatrepr(...data...)", + memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) + + { + int oldfree; + + sdsfree(x); + x = sdsnew("0"); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); + x = sdsMakeRoomFor(x,1); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); + oldfree = sh->free; + x[1] = '1'; + sdsIncrLen(x,1); + test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); + test_cond("sdsIncrLen() -- len", sh->len == 2); + test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); + } + } + test_report() + return 0; +} +#endif diff --git a/ext/hiredis-vip-0.3.0/sds.h b/ext/hiredis-vip-0.3.0/sds.h new file mode 100644 index 00000000..19a2abd3 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/sds.h @@ -0,0 +1,105 @@ +/* SDS (Simple Dynamic Strings), A C dynamic strings library. + * + * Copyright (c) 2006-2014, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SDS_H +#define __SDS_H + +#define SDS_MAX_PREALLOC (1024*1024) + +#include +#include +#ifdef _MSC_VER +#include "win32.h" +#endif + +typedef char *sds; + +struct sdshdr { + int len; + int free; + char buf[]; +}; + +static inline size_t sdslen(const sds s) { + struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); + return sh->len; +} + +static inline size_t sdsavail(const sds s) { + struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); + return sh->free; +} + +sds sdsnewlen(const void *init, size_t initlen); +sds sdsnew(const char *init); +sds sdsempty(void); +size_t sdslen(const sds s); +sds sdsdup(const sds s); +void sdsfree(sds s); +size_t sdsavail(const sds s); +sds sdsgrowzero(sds s, size_t len); +sds sdscatlen(sds s, const void *t, size_t len); +sds sdscat(sds s, const char *t); +sds sdscatsds(sds s, const sds t); +sds sdscpylen(sds s, const char *t, size_t len); +sds sdscpy(sds s, const char *t); + +sds sdscatvprintf(sds s, const char *fmt, va_list ap); +#ifdef __GNUC__ +sds sdscatprintf(sds s, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#else +sds sdscatprintf(sds s, const char *fmt, ...); +#endif + +sds sdscatfmt(sds s, char const *fmt, ...); +void sdstrim(sds s, const char *cset); +void sdsrange(sds s, int start, int end); +void sdsupdatelen(sds s); +void sdsclear(sds s); +int sdscmp(const sds s1, const sds s2); +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); +void sdsfreesplitres(sds *tokens, int count); +void sdstolower(sds s); +void sdstoupper(sds s); +sds sdsfromlonglong(long long value); +sds sdscatrepr(sds s, const char *p, size_t len); +sds *sdssplitargs(const char *line, int *argc); +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); +sds sdsjoin(char **argv, int argc, char *sep, size_t seplen); +sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); + +/* Low level functions exposed to the user API */ +sds sdsMakeRoomFor(sds s, size_t addlen); +void sdsIncrLen(sds s, int incr); +sds sdsRemoveFreeSpace(sds s); +size_t sdsAllocSize(sds s); + +#endif diff --git a/ext/hiredis-vip-0.3.0/test.c b/ext/hiredis-vip-0.3.0/test.c new file mode 100644 index 00000000..8fde5544 --- /dev/null +++ b/ext/hiredis-vip-0.3.0/test.c @@ -0,0 +1,806 @@ +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hiredis.h" +#include "net.h" + +enum connection_type { + CONN_TCP, + CONN_UNIX, + CONN_FD +}; + +struct config { + enum connection_type type; + + struct { + const char *host; + int port; + struct timeval timeout; + } tcp; + + struct { + const char *path; + } unix; +}; + +/* The following lines make up our testing "framework" :) */ +static int tests = 0, fails = 0; +#define test(_s) { printf("#%02d ", ++tests); printf(_s); } +#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;} + +static long long usec(void) { + struct timeval tv; + gettimeofday(&tv,NULL); + return (((long long)tv.tv_sec)*1000000)+tv.tv_usec; +} + +/* The assert() calls below have side effects, so we need assert() + * even if we are compiling without asserts (-DNDEBUG). */ +#ifdef NDEBUG +#undef assert +#define assert(e) (void)(e) +#endif + +static redisContext *select_database(redisContext *c) { + redisReply *reply; + + /* Switch to DB 9 for testing, now that we know we can chat. */ + reply = redisCommand(c,"SELECT 9"); + assert(reply != NULL); + freeReplyObject(reply); + + /* Make sure the DB is emtpy */ + reply = redisCommand(c,"DBSIZE"); + assert(reply != NULL); + if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 0) { + /* Awesome, DB 9 is empty and we can continue. */ + freeReplyObject(reply); + } else { + printf("Database #9 is not empty, test can not continue\n"); + exit(1); + } + + return c; +} + +static int disconnect(redisContext *c, int keep_fd) { + redisReply *reply; + + /* Make sure we're on DB 9. */ + reply = redisCommand(c,"SELECT 9"); + assert(reply != NULL); + freeReplyObject(reply); + reply = redisCommand(c,"FLUSHDB"); + assert(reply != NULL); + freeReplyObject(reply); + + /* Free the context as well, but keep the fd if requested. */ + if (keep_fd) + return redisFreeKeepFd(c); + redisFree(c); + return -1; +} + +static redisContext *connect(struct config config) { + redisContext *c = NULL; + + if (config.type == CONN_TCP) { + c = redisConnect(config.tcp.host, config.tcp.port); + } else if (config.type == CONN_UNIX) { + c = redisConnectUnix(config.unix.path); + } else if (config.type == CONN_FD) { + /* Create a dummy connection just to get an fd to inherit */ + redisContext *dummy_ctx = redisConnectUnix(config.unix.path); + if (dummy_ctx) { + int fd = disconnect(dummy_ctx, 1); + printf("Connecting to inherited fd %d\n", fd); + c = redisConnectFd(fd); + } + } else { + assert(NULL); + } + + if (c == NULL) { + printf("Connection error: can't allocate redis context\n"); + exit(1); + } else if (c->err) { + printf("Connection error: %s\n", c->errstr); + redisFree(c); + exit(1); + } + + return select_database(c); +} + +static void test_format_commands(void) { + char *cmd; + int len; + + test("Format command without interpolation: "); + len = redisFormatCommand(&cmd,"SET foo bar"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command with %%s string interpolation: "); + len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command with %%s and an empty string: "); + len = redisFormatCommand(&cmd,"SET %s %s","foo",""); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(0+2)); + free(cmd); + + test("Format command with an empty string in between proper interpolations: "); + len = redisFormatCommand(&cmd,"SET %s %s","","foo"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && + len == 4+4+(3+2)+4+(0+2)+4+(3+2)); + free(cmd); + + test("Format command with %%b string interpolation: "); + len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command with %%b and an empty string: "); + len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(0+2)); + free(cmd); + + test("Format command with literal %%: "); + len = redisFormatCommand(&cmd,"SET %% %%"); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && + len == 4+4+(3+2)+4+(1+2)+4+(1+2)); + free(cmd); + + /* Vararg width depends on the type. These tests make sure that the + * width is correctly determined using the format and subsequent varargs + * can correctly be interpolated. */ +#define INTEGER_WIDTH_TEST(fmt, type) do { \ + type value = 123; \ + test("Format command with printf-delegation (" #type "): "); \ + len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \ + test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \ + len == 4+5+(12+2)+4+(9+2)); \ + free(cmd); \ +} while(0) + +#define FLOAT_WIDTH_TEST(type) do { \ + type value = 123.0; \ + test("Format command with printf-delegation (" #type "): "); \ + len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \ + test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \ + len == 4+5+(12+2)+4+(9+2)); \ + free(cmd); \ +} while(0) + + INTEGER_WIDTH_TEST("d", int); + INTEGER_WIDTH_TEST("hhd", char); + INTEGER_WIDTH_TEST("hd", short); + INTEGER_WIDTH_TEST("ld", long); + INTEGER_WIDTH_TEST("lld", long long); + INTEGER_WIDTH_TEST("u", unsigned int); + INTEGER_WIDTH_TEST("hhu", unsigned char); + INTEGER_WIDTH_TEST("hu", unsigned short); + INTEGER_WIDTH_TEST("lu", unsigned long); + INTEGER_WIDTH_TEST("llu", unsigned long long); + FLOAT_WIDTH_TEST(float); + FLOAT_WIDTH_TEST(double); + + test("Format command with invalid printf format: "); + len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3); + test_cond(len == -1); + + const char *argv[3]; + argv[0] = "SET"; + argv[1] = "foo\0xxx"; + argv[2] = "bar"; + size_t lens[3] = { 3, 7, 3 }; + int argc = 3; + + test("Format command by passing argc/argv without lengths: "); + len = redisFormatCommandArgv(&cmd,argc,argv,NULL); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(3+2)+4+(3+2)); + free(cmd); + + test("Format command by passing argc/argv with lengths: "); + len = redisFormatCommandArgv(&cmd,argc,argv,lens); + test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && + len == 4+4+(3+2)+4+(7+2)+4+(3+2)); + free(cmd); +} + +static void test_append_formatted_commands(struct config config) { + redisContext *c; + redisReply *reply; + char *cmd; + int len; + + c = connect(config); + + test("Append format command: "); + + len = redisFormatCommand(&cmd, "SET foo bar"); + + test_cond(redisAppendFormattedCommand(c, cmd, len) == REDIS_OK); + + assert(redisGetReply(c, (void*)&reply) == REDIS_OK); + + free(cmd); + freeReplyObject(reply); + + disconnect(c, 0); +} + +static void test_reply_reader(void) { + redisReader *reader; + void *reply; + int ret; + int i; + + test("Error handling in reply parser: "); + reader = redisReaderCreate(); + redisReaderFeed(reader,(char*)"@foo\r\n",6); + ret = redisReaderGetReply(reader,NULL); + test_cond(ret == REDIS_ERR && + strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); + redisReaderFree(reader); + + /* when the reply already contains multiple items, they must be free'd + * on an error. valgrind will bark when this doesn't happen. */ + test("Memory cleanup in reply parser: "); + reader = redisReaderCreate(); + redisReaderFeed(reader,(char*)"*2\r\n",4); + redisReaderFeed(reader,(char*)"$5\r\nhello\r\n",11); + redisReaderFeed(reader,(char*)"@foo\r\n",6); + ret = redisReaderGetReply(reader,NULL); + test_cond(ret == REDIS_ERR && + strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); + redisReaderFree(reader); + + test("Set error on nested multi bulks with depth > 7: "); + reader = redisReaderCreate(); + + for (i = 0; i < 9; i++) { + redisReaderFeed(reader,(char*)"*1\r\n",4); + } + + ret = redisReaderGetReply(reader,NULL); + test_cond(ret == REDIS_ERR && + strncasecmp(reader->errstr,"No support for",14) == 0); + redisReaderFree(reader); + + test("Works with NULL functions for reply: "); + reader = redisReaderCreate(); + reader->fn = NULL; + redisReaderFeed(reader,(char*)"+OK\r\n",5); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); + redisReaderFree(reader); + + test("Works when a single newline (\\r\\n) covers two calls to feed: "); + reader = redisReaderCreate(); + reader->fn = NULL; + redisReaderFeed(reader,(char*)"+OK\r",4); + ret = redisReaderGetReply(reader,&reply); + assert(ret == REDIS_OK && reply == NULL); + redisReaderFeed(reader,(char*)"\n",1); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); + redisReaderFree(reader); + + test("Don't reset state after protocol error: "); + reader = redisReaderCreate(); + reader->fn = NULL; + redisReaderFeed(reader,(char*)"x",1); + ret = redisReaderGetReply(reader,&reply); + assert(ret == REDIS_ERR); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_ERR && reply == NULL); + redisReaderFree(reader); + + /* Regression test for issue #45 on GitHub. */ + test("Don't do empty allocation for empty multi bulk: "); + reader = redisReaderCreate(); + redisReaderFeed(reader,(char*)"*0\r\n",4); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_OK && + ((redisReply*)reply)->type == REDIS_REPLY_ARRAY && + ((redisReply*)reply)->elements == 0); + freeReplyObject(reply); + redisReaderFree(reader); +} + +static void test_free_null(void) { + void *redisContext = NULL; + void *reply = NULL; + + test("Don't fail when redisFree is passed a NULL value: "); + redisFree(redisContext); + test_cond(redisContext == NULL); + + test("Don't fail when freeReplyObject is passed a NULL value: "); + freeReplyObject(reply); + test_cond(reply == NULL); +} + +static void test_blocking_connection_errors(void) { + redisContext *c; + + test("Returns error when host cannot be resolved: "); + c = redisConnect((char*)"idontexist.test", 6379); + test_cond(c->err == REDIS_ERR_OTHER && + (strcmp(c->errstr,"Name or service not known") == 0 || + strcmp(c->errstr,"Can't resolve: idontexist.test") == 0 || + strcmp(c->errstr,"nodename nor servname provided, or not known") == 0 || + strcmp(c->errstr,"No address associated with hostname") == 0 || + strcmp(c->errstr,"Temporary failure in name resolution") == 0 || + strcmp(c->errstr,"no address associated with name") == 0)); + redisFree(c); + + test("Returns error when the port is not open: "); + c = redisConnect((char*)"localhost", 1); + test_cond(c->err == REDIS_ERR_IO && + strcmp(c->errstr,"Connection refused") == 0); + redisFree(c); + + test("Returns error when the unix socket path doesn't accept connections: "); + c = redisConnectUnix((char*)"/tmp/idontexist.sock"); + test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */ + redisFree(c); +} + +static void test_blocking_connection(struct config config) { + redisContext *c; + redisReply *reply; + + c = connect(config); + + test("Is able to deliver commands: "); + reply = redisCommand(c,"PING"); + test_cond(reply->type == REDIS_REPLY_STATUS && + strcasecmp(reply->str,"pong") == 0) + freeReplyObject(reply); + + test("Is a able to send commands verbatim: "); + reply = redisCommand(c,"SET foo bar"); + test_cond (reply->type == REDIS_REPLY_STATUS && + strcasecmp(reply->str,"ok") == 0) + freeReplyObject(reply); + + test("%%s String interpolation works: "); + reply = redisCommand(c,"SET %s %s","foo","hello world"); + freeReplyObject(reply); + reply = redisCommand(c,"GET foo"); + test_cond(reply->type == REDIS_REPLY_STRING && + strcmp(reply->str,"hello world") == 0); + freeReplyObject(reply); + + test("%%b String interpolation works: "); + reply = redisCommand(c,"SET %b %b","foo",(size_t)3,"hello\x00world",(size_t)11); + freeReplyObject(reply); + reply = redisCommand(c,"GET foo"); + test_cond(reply->type == REDIS_REPLY_STRING && + memcmp(reply->str,"hello\x00world",11) == 0) + + test("Binary reply length is correct: "); + test_cond(reply->len == 11) + freeReplyObject(reply); + + test("Can parse nil replies: "); + reply = redisCommand(c,"GET nokey"); + test_cond(reply->type == REDIS_REPLY_NIL) + freeReplyObject(reply); + + /* test 7 */ + test("Can parse integer replies: "); + reply = redisCommand(c,"INCR mycounter"); + test_cond(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) + freeReplyObject(reply); + + test("Can parse multi bulk replies: "); + freeReplyObject(redisCommand(c,"LPUSH mylist foo")); + freeReplyObject(redisCommand(c,"LPUSH mylist bar")); + reply = redisCommand(c,"LRANGE mylist 0 -1"); + test_cond(reply->type == REDIS_REPLY_ARRAY && + reply->elements == 2 && + !memcmp(reply->element[0]->str,"bar",3) && + !memcmp(reply->element[1]->str,"foo",3)) + freeReplyObject(reply); + + /* m/e with multi bulk reply *before* other reply. + * specifically test ordering of reply items to parse. */ + test("Can handle nested multi bulk replies: "); + freeReplyObject(redisCommand(c,"MULTI")); + freeReplyObject(redisCommand(c,"LRANGE mylist 0 -1")); + freeReplyObject(redisCommand(c,"PING")); + reply = (redisCommand(c,"EXEC")); + test_cond(reply->type == REDIS_REPLY_ARRAY && + reply->elements == 2 && + reply->element[0]->type == REDIS_REPLY_ARRAY && + reply->element[0]->elements == 2 && + !memcmp(reply->element[0]->element[0]->str,"bar",3) && + !memcmp(reply->element[0]->element[1]->str,"foo",3) && + reply->element[1]->type == REDIS_REPLY_STATUS && + strcasecmp(reply->element[1]->str,"pong") == 0); + freeReplyObject(reply); + + disconnect(c, 0); +} + +static void test_blocking_connection_timeouts(struct config config) { + redisContext *c; + redisReply *reply; + ssize_t s; + const char *cmd = "DEBUG SLEEP 3\r\n"; + struct timeval tv; + + c = connect(config); + test("Successfully completes a command when the timeout is not exceeded: "); + reply = redisCommand(c,"SET foo fast"); + freeReplyObject(reply); + tv.tv_sec = 0; + tv.tv_usec = 10000; + redisSetTimeout(c, tv); + reply = redisCommand(c, "GET foo"); + test_cond(reply != NULL && reply->type == REDIS_REPLY_STRING && memcmp(reply->str, "fast", 4) == 0); + freeReplyObject(reply); + disconnect(c, 0); + + c = connect(config); + test("Does not return a reply when the command times out: "); + s = write(c->fd, cmd, strlen(cmd)); + tv.tv_sec = 0; + tv.tv_usec = 10000; + redisSetTimeout(c, tv); + reply = redisCommand(c, "GET foo"); + test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0); + freeReplyObject(reply); + + test("Reconnect properly reconnects after a timeout: "); + redisReconnect(c); + reply = redisCommand(c, "PING"); + test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); + freeReplyObject(reply); + + test("Reconnect properly uses owned parameters: "); + config.tcp.host = "foo"; + config.unix.path = "foo"; + redisReconnect(c); + reply = redisCommand(c, "PING"); + test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); + freeReplyObject(reply); + + disconnect(c, 0); +} + +static void test_blocking_io_errors(struct config config) { + redisContext *c; + redisReply *reply; + void *_reply; + int major, minor; + + /* Connect to target given by config. */ + c = connect(config); + { + /* Find out Redis version to determine the path for the next test */ + const char *field = "redis_version:"; + char *p, *eptr; + + reply = redisCommand(c,"INFO"); + p = strstr(reply->str,field); + major = strtol(p+strlen(field),&eptr,10); + p = eptr+1; /* char next to the first "." */ + minor = strtol(p,&eptr,10); + freeReplyObject(reply); + } + + test("Returns I/O error when the connection is lost: "); + reply = redisCommand(c,"QUIT"); + if (major > 2 || (major == 2 && minor > 0)) { + /* > 2.0 returns OK on QUIT and read() should be issued once more + * to know the descriptor is at EOF. */ + test_cond(strcasecmp(reply->str,"OK") == 0 && + redisGetReply(c,&_reply) == REDIS_ERR); + freeReplyObject(reply); + } else { + test_cond(reply == NULL); + } + + /* On 2.0, QUIT will cause the connection to be closed immediately and + * the read(2) for the reply on QUIT will set the error to EOF. + * On >2.0, QUIT will return with OK and another read(2) needed to be + * issued to find out the socket was closed by the server. In both + * conditions, the error will be set to EOF. */ + assert(c->err == REDIS_ERR_EOF && + strcmp(c->errstr,"Server closed the connection") == 0); + redisFree(c); + + c = connect(config); + test("Returns I/O error on socket timeout: "); + struct timeval tv = { 0, 1000 }; + assert(redisSetTimeout(c,tv) == REDIS_OK); + test_cond(redisGetReply(c,&_reply) == REDIS_ERR && + c->err == REDIS_ERR_IO && errno == EAGAIN); + redisFree(c); +} + +static void test_invalid_timeout_errors(struct config config) { + redisContext *c; + + test("Set error when an invalid timeout usec value is given to redisConnectWithTimeout: "); + + config.tcp.timeout.tv_sec = 0; + config.tcp.timeout.tv_usec = 10000001; + + c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); + + test_cond(c->err == REDIS_ERR_IO); + redisFree(c); + + test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: "); + + config.tcp.timeout.tv_sec = (((LONG_MAX) - 999) / 1000) + 1; + config.tcp.timeout.tv_usec = 0; + + c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); + + test_cond(c->err == REDIS_ERR_IO); + redisFree(c); +} + +static void test_throughput(struct config config) { + redisContext *c = connect(config); + redisReply **replies; + int i, num; + long long t1, t2; + + test("Throughput:\n"); + for (i = 0; i < 500; i++) + freeReplyObject(redisCommand(c,"LPUSH mylist foo")); + + num = 1000; + replies = malloc(sizeof(redisReply*)*num); + t1 = usec(); + for (i = 0; i < num; i++) { + replies[i] = redisCommand(c,"PING"); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); + + replies = malloc(sizeof(redisReply*)*num); + t1 = usec(); + for (i = 0; i < num; i++) { + replies[i] = redisCommand(c,"LRANGE mylist 0 499"); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); + assert(replies[i] != NULL && replies[i]->elements == 500); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); + + num = 10000; + replies = malloc(sizeof(redisReply*)*num); + for (i = 0; i < num; i++) + redisAppendCommand(c,"PING"); + t1 = usec(); + for (i = 0; i < num; i++) { + assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); + + replies = malloc(sizeof(redisReply*)*num); + for (i = 0; i < num; i++) + redisAppendCommand(c,"LRANGE mylist 0 499"); + t1 = usec(); + for (i = 0; i < num; i++) { + assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); + assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); + assert(replies[i] != NULL && replies[i]->elements == 500); + } + t2 = usec(); + for (i = 0; i < num; i++) freeReplyObject(replies[i]); + free(replies); + printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); + + disconnect(c, 0); +} + +// static long __test_callback_flags = 0; +// static void __test_callback(redisContext *c, void *privdata) { +// ((void)c); +// /* Shift to detect execution order */ +// __test_callback_flags <<= 8; +// __test_callback_flags |= (long)privdata; +// } +// +// static void __test_reply_callback(redisContext *c, redisReply *reply, void *privdata) { +// ((void)c); +// /* Shift to detect execution order */ +// __test_callback_flags <<= 8; +// __test_callback_flags |= (long)privdata; +// if (reply) freeReplyObject(reply); +// } +// +// static redisContext *__connect_nonblock() { +// /* Reset callback flags */ +// __test_callback_flags = 0; +// return redisConnectNonBlock("127.0.0.1", port, NULL); +// } +// +// static void test_nonblocking_connection() { +// redisContext *c; +// int wdone = 0; +// +// test("Calls command callback when command is issued: "); +// c = __connect_nonblock(); +// redisSetCommandCallback(c,__test_callback,(void*)1); +// redisCommand(c,"PING"); +// test_cond(__test_callback_flags == 1); +// redisFree(c); +// +// test("Calls disconnect callback on redisDisconnect: "); +// c = __connect_nonblock(); +// redisSetDisconnectCallback(c,__test_callback,(void*)2); +// redisDisconnect(c); +// test_cond(__test_callback_flags == 2); +// redisFree(c); +// +// test("Calls disconnect callback and free callback on redisFree: "); +// c = __connect_nonblock(); +// redisSetDisconnectCallback(c,__test_callback,(void*)2); +// redisSetFreeCallback(c,__test_callback,(void*)4); +// redisFree(c); +// test_cond(__test_callback_flags == ((2 << 8) | 4)); +// +// test("redisBufferWrite against empty write buffer: "); +// c = __connect_nonblock(); +// test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1); +// redisFree(c); +// +// test("redisBufferWrite against not yet connected fd: "); +// c = __connect_nonblock(); +// redisCommand(c,"PING"); +// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && +// strncmp(c->error,"write:",6) == 0); +// redisFree(c); +// +// test("redisBufferWrite against closed fd: "); +// c = __connect_nonblock(); +// redisCommand(c,"PING"); +// redisDisconnect(c); +// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && +// strncmp(c->error,"write:",6) == 0); +// redisFree(c); +// +// test("Process callbacks in the right sequence: "); +// c = __connect_nonblock(); +// redisCommandWithCallback(c,__test_reply_callback,(void*)1,"PING"); +// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); +// redisCommandWithCallback(c,__test_reply_callback,(void*)3,"PING"); +// +// /* Write output buffer */ +// wdone = 0; +// while(!wdone) { +// usleep(500); +// redisBufferWrite(c,&wdone); +// } +// +// /* Read until at least one callback is executed (the 3 replies will +// * arrive in a single packet, causing all callbacks to be executed in +// * a single pass). */ +// while(__test_callback_flags == 0) { +// assert(redisBufferRead(c) == REDIS_OK); +// redisProcessCallbacks(c); +// } +// test_cond(__test_callback_flags == 0x010203); +// redisFree(c); +// +// test("redisDisconnect executes pending callbacks with NULL reply: "); +// c = __connect_nonblock(); +// redisSetDisconnectCallback(c,__test_callback,(void*)1); +// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); +// redisDisconnect(c); +// test_cond(__test_callback_flags == 0x0201); +// redisFree(c); +// } + +int main(int argc, char **argv) { + struct config cfg = { + .tcp = { + .host = "127.0.0.1", + .port = 6379 + }, + .unix = { + .path = "/tmp/redis.sock" + } + }; + int throughput = 1; + int test_inherit_fd = 1; + + /* Ignore broken pipe signal (for I/O error tests). */ + signal(SIGPIPE, SIG_IGN); + + /* Parse command line options. */ + argv++; argc--; + while (argc) { + if (argc >= 2 && !strcmp(argv[0],"-h")) { + argv++; argc--; + cfg.tcp.host = argv[0]; + } else if (argc >= 2 && !strcmp(argv[0],"-p")) { + argv++; argc--; + cfg.tcp.port = atoi(argv[0]); + } else if (argc >= 2 && !strcmp(argv[0],"-s")) { + argv++; argc--; + cfg.unix.path = argv[0]; + } else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) { + throughput = 0; + } else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) { + test_inherit_fd = 0; + } else { + fprintf(stderr, "Invalid argument: %s\n", argv[0]); + exit(1); + } + argv++; argc--; + } + + test_format_commands(); + test_reply_reader(); + test_blocking_connection_errors(); + test_free_null(); + + printf("\nTesting against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port); + cfg.type = CONN_TCP; + test_blocking_connection(cfg); + test_blocking_connection_timeouts(cfg); + test_blocking_io_errors(cfg); + test_invalid_timeout_errors(cfg); + test_append_formatted_commands(cfg); + if (throughput) test_throughput(cfg); + + printf("\nTesting against Unix socket connection (%s):\n", cfg.unix.path); + cfg.type = CONN_UNIX; + test_blocking_connection(cfg); + test_blocking_connection_timeouts(cfg); + test_blocking_io_errors(cfg); + if (throughput) test_throughput(cfg); + + if (test_inherit_fd) { + printf("\nTesting against inherited fd (%s):\n", cfg.unix.path); + cfg.type = CONN_FD; + test_blocking_connection(cfg); + } + + + if (fails) { + printf("*** %d TESTS FAILED ***\n", fails); + return 1; + } + + printf("ALL TESTS PASSED\n"); + return 0; +} diff --git a/ext/hiredis-vip-0.3.0/win32.h b/ext/hiredis-vip-0.3.0/win32.h new file mode 100644 index 00000000..1a27c18f --- /dev/null +++ b/ext/hiredis-vip-0.3.0/win32.h @@ -0,0 +1,42 @@ +#ifndef _WIN32_HELPER_INCLUDE +#define _WIN32_HELPER_INCLUDE +#ifdef _MSC_VER + +#ifndef inline +#define inline __inline +#endif + +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +#ifndef snprintf +#define snprintf c99_snprintf + +__inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char* str, size_t size, const char* format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(str, size, format, ap); + va_end(ap); + + return count; +} +#endif + +#endif +#endif \ No newline at end of file diff --git a/ext/installfiles/linux/zerotier-containerized/Dockerfile b/ext/installfiles/linux/zerotier-containerized/Dockerfile index fd18eebb..3d580566 100644 --- a/ext/installfiles/linux/zerotier-containerized/Dockerfile +++ b/ext/installfiles/linux/zerotier-containerized/Dockerfile @@ -7,17 +7,13 @@ FROM debian:buster-slim as builder RUN apt-get update && apt-get install -y curl gnupg RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 0x1657198823e52a61 && \ echo "deb http://download.zerotier.com/debian/buster buster main" > /etc/apt/sources.list.d/zerotier.list -RUN apt-get update && apt-get install -y zerotier-one=1.2.12 -RUN curl https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/ext/installfiles/linux/zerotier-containerized/main.sh > /var/lib/zerotier-one/main.sh +RUN apt-get update && apt-get install -y zerotier-one=1.4.4 +COPY ext/installfiles/linux/zerotier-containerized/main.sh /var/lib/zerotier-one/main.sh -FROM alpine:latest -LABEL version="1.2.12" +FROM debian:buster-slim +LABEL version="1.4.4" LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts." -# Uncomment to build in container -# RUN apk add --update alpine-sdk linux-headers -RUN apk add --update libgcc libstdc++ - # ZeroTier relies on UDP port 9993 EXPOSE 9993/udp diff --git a/ext/installfiles/mac/ZeroTier One.pkgproj b/ext/installfiles/mac/ZeroTier One.pkgproj index 2bd19123..c55ae733 100755 --- a/ext/installfiles/mac/ZeroTier One.pkgproj +++ b/ext/installfiles/mac/ZeroTier One.pkgproj @@ -717,7 +717,7 @@ USE_HFS+_COMPRESSION VERSION - 1.4.2 + 1.4.6 TYPE 0 diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index 1694f87f..61b6ec33 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -27,10 +27,10 @@ - + - + @@ -64,7 +64,7 @@ - + @@ -454,7 +454,7 @@ - + diff --git a/ext/librabbitmq/centos_x64/include/amqp.h b/ext/librabbitmq/centos_x64/include/amqp.h deleted file mode 100644 index 2983b166..00000000 --- a/ext/librabbitmq/centos_x64/include/amqp.h +++ /dev/null @@ -1,2538 +0,0 @@ -/** \file */ -/* - * ***** BEGIN LICENSE BLOCK ***** - * Version: MIT - * - * Portions created by Alan Antonuk are Copyright (c) 2012-2014 - * Alan Antonuk. All Rights Reserved. - * - * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc. - * All Rights Reserved. - * - * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010 - * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * ***** END LICENSE BLOCK ***** - */ - -#ifndef AMQP_H -#define AMQP_H - -/** \cond HIDE_FROM_DOXYGEN */ - -#ifdef __cplusplus -#define AMQP_BEGIN_DECLS extern "C" { -#define AMQP_END_DECLS } -#else -#define AMQP_BEGIN_DECLS -#define AMQP_END_DECLS -#endif - -/* - * \internal - * Important API decorators: - * AMQP_PUBLIC_FUNCTION - a public API function - * AMQP_PUBLIC_VARIABLE - a public API external variable - * AMQP_CALL - calling convension (used on Win32) - */ - -#if defined(_WIN32) && defined(_MSC_VER) -#if defined(AMQP_BUILD) && !defined(AMQP_STATIC) -#define AMQP_PUBLIC_FUNCTION __declspec(dllexport) -#define AMQP_PUBLIC_VARIABLE __declspec(dllexport) extern -#else -#define AMQP_PUBLIC_FUNCTION -#if !defined(AMQP_STATIC) -#define AMQP_PUBLIC_VARIABLE __declspec(dllimport) extern -#else -#define AMQP_PUBLIC_VARIABLE extern -#endif -#endif -#define AMQP_CALL __cdecl - -#elif defined(_WIN32) && defined(__BORLANDC__) -#if defined(AMQP_BUILD) && !defined(AMQP_STATIC) -#define AMQP_PUBLIC_FUNCTION __declspec(dllexport) -#define AMQP_PUBLIC_VARIABLE __declspec(dllexport) extern -#else -#define AMQP_PUBLIC_FUNCTION -#if !defined(AMQP_STATIC) -#define AMQP_PUBLIC_VARIABLE __declspec(dllimport) extern -#else -#define AMQP_PUBLIC_VARIABLE extern -#endif -#endif -#define AMQP_CALL __cdecl - -#elif defined(_WIN32) && defined(__MINGW32__) -#if defined(AMQP_BUILD) && !defined(AMQP_STATIC) -#define AMQP_PUBLIC_FUNCTION __declspec(dllexport) -#define AMQP_PUBLIC_VARIABLE __declspec(dllexport) extern -#else -#define AMQP_PUBLIC_FUNCTION -#if !defined(AMQP_STATIC) -#define AMQP_PUBLIC_VARIABLE __declspec(dllimport) extern -#else -#define AMQP_PUBLIC_VARIABLE extern -#endif -#endif -#define AMQP_CALL __cdecl - -#elif defined(_WIN32) && defined(__CYGWIN__) -#if defined(AMQP_BUILD) && !defined(AMQP_STATIC) -#define AMQP_PUBLIC_FUNCTION __declspec(dllexport) -#define AMQP_PUBLIC_VARIABLE __declspec(dllexport) -#else -#define AMQP_PUBLIC_FUNCTION -#if !defined(AMQP_STATIC) -#define AMQP_PUBLIC_VARIABLE __declspec(dllimport) extern -#else -#define AMQP_PUBLIC_VARIABLE extern -#endif -#endif -#define AMQP_CALL __cdecl - -#elif defined(__GNUC__) && __GNUC__ >= 4 -#define AMQP_PUBLIC_FUNCTION __attribute__((visibility("default"))) -#define AMQP_PUBLIC_VARIABLE __attribute__((visibility("default"))) extern -#define AMQP_CALL -#else -#define AMQP_PUBLIC_FUNCTION -#define AMQP_PUBLIC_VARIABLE extern -#define AMQP_CALL -#endif - -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) -#define AMQP_DEPRECATED(function) function __attribute__((__deprecated__)) -#elif defined(_MSC_VER) -#define AMQP_DEPRECATED(function) __declspec(deprecated) function -#else -#define AMQP_DEPRECATED(function) -#endif - -/* Define ssize_t on Win32/64 platforms - See: http://lists.cs.uiuc.edu/pipermail/llvmdev/2010-April/030649.html for - details - */ -#if !defined(_W64) -#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -#define _W64 __w64 -#else -#define _W64 -#endif -#endif - -#ifdef _MSC_VER -#ifdef _WIN64 -typedef __int64 ssize_t; -#else -typedef _W64 int ssize_t; -#endif -#endif - -#if defined(_WIN32) && defined(__MINGW32__) -#include -#endif - -/** \endcond */ - -#include -#include - -struct timeval; - -AMQP_BEGIN_DECLS - -/** - * \def AMQP_VERSION_MAJOR - * - * Major library version number compile-time constant - * - * The major version is incremented when backwards incompatible API changes - * are made. - * - * \sa AMQP_VERSION, AMQP_VERSION_STRING - * - * \since v0.4.0 - */ - -/** - * \def AMQP_VERSION_MINOR - * - * Minor library version number compile-time constant - * - * The minor version is incremented when new APIs are added. Existing APIs - * are left alone. - * - * \sa AMQP_VERSION, AMQP_VERSION_STRING - * - * \since v0.4.0 - */ - -/** - * \def AMQP_VERSION_PATCH - * - * Patch library version number compile-time constant - * - * The patch version is incremented when library code changes, but the API - * is not changed. - * - * \sa AMQP_VERSION, AMQP_VERSION_STRING - * - * \since v0.4.0 - */ - -/** - * \def AMQP_VERSION_IS_RELEASE - * - * Version constant set to 1 for tagged release, 0 otherwise - * - * NOTE: versions that are not tagged releases are not guaranteed to be API/ABI - * compatible with older releases, and may change commit-to-commit. - * - * \sa AMQP_VERSION, AMQP_VERSION_STRING - * - * \since v0.4.0 - */ -/* - * Developer note: when changing these, be sure to update SOVERSION constants - * in CMakeLists.txt and configure.ac - */ - -#define AMQP_VERSION_MAJOR 0 -#define AMQP_VERSION_MINOR 10 -#define AMQP_VERSION_PATCH 0 -#define AMQP_VERSION_IS_RELEASE 0 - -/** - * \def AMQP_VERSION_CODE - * - * Helper macro to geneate a packed version code suitable for - * comparison with AMQP_VERSION. - * - * \sa amqp_version_number() AMQP_VERSION_MAJOR, AMQP_VERSION_MINOR, - * AMQP_VERSION_PATCH, AMQP_VERSION_IS_RELEASE, AMQP_VERSION - * - * \since v0.6.1 - */ -#define AMQP_VERSION_CODE(major, minor, patch, release) \ - ((major << 24) | (minor << 16) | (patch << 8) | (release)) - -/** - * \def AMQP_VERSION - * - * Packed version number - * - * AMQP_VERSION is a 4-byte unsigned integer with the most significant byte - * set to AMQP_VERSION_MAJOR, the second most significant byte set to - * AMQP_VERSION_MINOR, third most significant byte set to AMQP_VERSION_PATCH, - * and the lowest byte set to AMQP_VERSION_IS_RELEASE. - * - * For example version 2.3.4 which is released version would be encoded as - * 0x02030401 - * - * \sa amqp_version_number() AMQP_VERSION_MAJOR, AMQP_VERSION_MINOR, - * AMQP_VERSION_PATCH, AMQP_VERSION_IS_RELEASE, AMQP_VERSION_CODE - * - * \since v0.4.0 - */ -#define AMQP_VERSION \ - AMQP_VERSION_CODE(AMQP_VERSION_MAJOR, AMQP_VERSION_MINOR, \ - AMQP_VERSION_PATCH, AMQP_VERSION_IS_RELEASE) - -/** \cond HIDE_FROM_DOXYGEN */ -#define AMQ_STRINGIFY(s) AMQ_STRINGIFY_HELPER(s) -#define AMQ_STRINGIFY_HELPER(s) #s - -#define AMQ_VERSION_STRING \ - AMQ_STRINGIFY(AMQP_VERSION_MAJOR) \ - "." AMQ_STRINGIFY(AMQP_VERSION_MINOR) "." AMQ_STRINGIFY(AMQP_VERSION_PATCH) -/** \endcond */ - -/** - * \def AMQP_VERSION_STRING - * - * Version string compile-time constant - * - * Non-released versions of the library will have "-pre" appended to the - * version string - * - * \sa amqp_version() - * - * \since v0.4.0 - */ -#if AMQP_VERSION_IS_RELEASE -#define AMQP_VERSION_STRING AMQ_VERSION_STRING -#else -#define AMQP_VERSION_STRING AMQ_VERSION_STRING "-pre" -#endif - -/** - * Returns the rabbitmq-c version as a packed integer. - * - * See \ref AMQP_VERSION - * - * \return packed 32-bit integer representing version of library at runtime - * - * \sa AMQP_VERSION, amqp_version() - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -uint32_t AMQP_CALL amqp_version_number(void); - -/** - * Returns the rabbitmq-c version as a string. - * - * See \ref AMQP_VERSION_STRING - * - * \return a statically allocated string describing the version of rabbitmq-c. - * - * \sa amqp_version_number(), AMQP_VERSION_STRING, AMQP_VERSION - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -char const *AMQP_CALL amqp_version(void); - -/** - * \def AMQP_DEFAULT_FRAME_SIZE - * - * Default frame size (128Kb) - * - * \sa amqp_login(), amqp_login_with_properties() - * - * \since v0.4.0 - */ -#define AMQP_DEFAULT_FRAME_SIZE 131072 - -/** - * \def AMQP_DEFAULT_MAX_CHANNELS - * - * Default maximum number of channels (2047, RabbitMQ default limit of 2048, - * minus 1 for channel 0). RabbitMQ set a default limit of 2048 channels per - * connection in v3.7.5 to prevent broken clients from leaking too many - * channels. - * - * \sa amqp_login(), amqp_login_with_properties() - * - * \since v0.4.0 - */ -#define AMQP_DEFAULT_MAX_CHANNELS 2047 - -/** - * \def AMQP_DEFAULT_HEARTBEAT - * - * Default heartbeat interval (0, heartbeat disabled) - * - * \sa amqp_login(), amqp_login_with_properties() - * - * \since v0.4.0 - */ -#define AMQP_DEFAULT_HEARTBEAT 0 - -/** - * \def AMQP_DEFAULT_VHOST - * - * Default RabbitMQ vhost: "/" - * - * \sa amqp_login(), amqp_login_with_properties() - * - * \since v0.9.0 - */ -#define AMQP_DEFAULT_VHOST "/" - -/** - * boolean type 0 = false, true otherwise - * - * \since v0.1 - */ -typedef int amqp_boolean_t; - -/** - * Method number - * - * \since v0.1 - */ -typedef uint32_t amqp_method_number_t; - -/** - * Bitmask for flags - * - * \since v0.1 - */ -typedef uint32_t amqp_flags_t; - -/** - * Channel type - * - * \since v0.1 - */ -typedef uint16_t amqp_channel_t; - -/** - * Buffer descriptor - * - * \since v0.1 - */ -typedef struct amqp_bytes_t_ { - size_t len; /**< length of the buffer in bytes */ - void *bytes; /**< pointer to the beginning of the buffer */ -} amqp_bytes_t; - -/** - * Decimal data type - * - * \since v0.1 - */ -typedef struct amqp_decimal_t_ { - uint8_t decimals; /**< the location of the decimal point */ - uint32_t value; /**< the value before the decimal point is applied */ -} amqp_decimal_t; - -/** - * AMQP field table - * - * An AMQP field table is a set of key-value pairs. - * A key is a UTF-8 encoded string up to 128 bytes long, and are not null - * terminated. - * A value can be one of several different datatypes. \sa - * amqp_field_value_kind_t - * - * \sa amqp_table_entry_t - * - * \since v0.1 - */ -typedef struct amqp_table_t_ { - int num_entries; /**< length of entries array */ - struct amqp_table_entry_t_ *entries; /**< an array of table entries */ -} amqp_table_t; - -/** - * An AMQP Field Array - * - * A repeated set of field values, all must be of the same type - * - * \since v0.1 - */ -typedef struct amqp_array_t_ { - int num_entries; /**< Number of entries in the table */ - struct amqp_field_value_t_ *entries; /**< linked list of field values */ -} amqp_array_t; - -/* - 0-9 0-9-1 Qpid/Rabbit Type Remarks ---------------------------------------------------------------------------- - t t Boolean - b b Signed 8-bit - B Unsigned 8-bit - U s Signed 16-bit (A1) - u Unsigned 16-bit - I I I Signed 32-bit - i Unsigned 32-bit - L l Signed 64-bit (B) - l Unsigned 64-bit - f f 32-bit float - d d 64-bit float - D D D Decimal - s Short string (A2) - S S S Long string - A Nested Array - T T T Timestamp (u64) - F F F Nested Table - V V V Void - x Byte array - -Remarks: - - A1, A2: Notice how the types **CONFLICT** here. In Qpid and Rabbit, - 's' means a signed 16-bit integer; in 0-9-1, it means a - short string. - - B: Notice how the signednesses **CONFLICT** here. In Qpid and Rabbit, - 'l' means a signed 64-bit integer; in 0-9-1, it means an unsigned - 64-bit integer. - -I'm going with the Qpid/Rabbit types, where there's a conflict, and -the 0-9-1 types otherwise. 0-8 is a subset of 0-9, which is a subset -of the other two, so this will work for both 0-8 and 0-9-1 branches of -the code. -*/ - -/** - * A field table value - * - * \since v0.1 - */ -typedef struct amqp_field_value_t_ { - uint8_t kind; /**< the type of the entry /sa amqp_field_value_kind_t */ - union { - amqp_boolean_t boolean; /**< boolean type AMQP_FIELD_KIND_BOOLEAN */ - int8_t i8; /**< int8_t type AMQP_FIELD_KIND_I8 */ - uint8_t u8; /**< uint8_t type AMQP_FIELD_KIND_U8 */ - int16_t i16; /**< int16_t type AMQP_FIELD_KIND_I16 */ - uint16_t u16; /**< uint16_t type AMQP_FIELD_KIND_U16 */ - int32_t i32; /**< int32_t type AMQP_FIELD_KIND_I32 */ - uint32_t u32; /**< uint32_t type AMQP_FIELD_KIND_U32 */ - int64_t i64; /**< int64_t type AMQP_FIELD_KIND_I64 */ - uint64_t u64; /**< uint64_t type AMQP_FIELD_KIND_U64, - AMQP_FIELD_KIND_TIMESTAMP */ - float f32; /**< float type AMQP_FIELD_KIND_F32 */ - double f64; /**< double type AMQP_FIELD_KIND_F64 */ - amqp_decimal_t decimal; /**< amqp_decimal_t AMQP_FIELD_KIND_DECIMAL */ - amqp_bytes_t bytes; /**< amqp_bytes_t type AMQP_FIELD_KIND_UTF8, - AMQP_FIELD_KIND_BYTES */ - amqp_table_t table; /**< amqp_table_t type AMQP_FIELD_KIND_TABLE */ - amqp_array_t array; /**< amqp_array_t type AMQP_FIELD_KIND_ARRAY */ - } value; /**< a union of the value */ -} amqp_field_value_t; - -/** - * An entry in a field-table - * - * \sa amqp_table_encode(), amqp_table_decode(), amqp_table_clone() - * - * \since v0.1 - */ -typedef struct amqp_table_entry_t_ { - amqp_bytes_t key; /**< the table entry key. Its a null-terminated UTF-8 - * string, with a maximum size of 128 bytes */ - amqp_field_value_t value; /**< the table entry values */ -} amqp_table_entry_t; - -/** - * Field value types - * - * \since v0.1 - */ -typedef enum { - AMQP_FIELD_KIND_BOOLEAN = - 't', /**< boolean type. 0 = false, 1 = true @see amqp_boolean_t */ - AMQP_FIELD_KIND_I8 = 'b', /**< 8-bit signed integer, datatype: int8_t */ - AMQP_FIELD_KIND_U8 = 'B', /**< 8-bit unsigned integer, datatype: uint8_t */ - AMQP_FIELD_KIND_I16 = 's', /**< 16-bit signed integer, datatype: int16_t */ - AMQP_FIELD_KIND_U16 = 'u', /**< 16-bit unsigned integer, datatype: uint16_t */ - AMQP_FIELD_KIND_I32 = 'I', /**< 32-bit signed integer, datatype: int32_t */ - AMQP_FIELD_KIND_U32 = 'i', /**< 32-bit unsigned integer, datatype: uint32_t */ - AMQP_FIELD_KIND_I64 = 'l', /**< 64-bit signed integer, datatype: int64_t */ - AMQP_FIELD_KIND_U64 = 'L', /**< 64-bit unsigned integer, datatype: uint64_t */ - AMQP_FIELD_KIND_F32 = - 'f', /**< single-precision floating point value, datatype: float */ - AMQP_FIELD_KIND_F64 = - 'd', /**< double-precision floating point value, datatype: double */ - AMQP_FIELD_KIND_DECIMAL = - 'D', /**< amqp-decimal value, datatype: amqp_decimal_t */ - AMQP_FIELD_KIND_UTF8 = 'S', /**< UTF-8 null-terminated character string, - datatype: amqp_bytes_t */ - AMQP_FIELD_KIND_ARRAY = 'A', /**< field array (repeated values of another - datatype. datatype: amqp_array_t */ - AMQP_FIELD_KIND_TIMESTAMP = 'T', /**< 64-bit timestamp. datatype uint64_t */ - AMQP_FIELD_KIND_TABLE = 'F', /**< field table. encapsulates a table inside a - table entry. datatype: amqp_table_t */ - AMQP_FIELD_KIND_VOID = 'V', /**< empty entry */ - AMQP_FIELD_KIND_BYTES = - 'x' /**< unformatted byte string, datatype: amqp_bytes_t */ -} amqp_field_value_kind_t; - -/** - * A list of allocation blocks - * - * \since v0.1 - */ -typedef struct amqp_pool_blocklist_t_ { - int num_blocks; /**< Number of blocks in the block list */ - void **blocklist; /**< Array of memory blocks */ -} amqp_pool_blocklist_t; - -/** - * A memory pool - * - * \since v0.1 - */ -typedef struct amqp_pool_t_ { - size_t pagesize; /**< the size of the page in bytes. Allocations less than or - * equal to this size are allocated in the pages block list. - * Allocations greater than this are allocated in their own - * own block in the large_blocks block list */ - - amqp_pool_blocklist_t pages; /**< blocks that are the size of pagesize */ - amqp_pool_blocklist_t - large_blocks; /**< allocations larger than the pagesize */ - - int next_page; /**< an index to the next unused page block */ - char *alloc_block; /**< pointer to the current allocation block */ - size_t alloc_used; /**< number of bytes in the current allocation block that - has been used */ -} amqp_pool_t; - -/** - * An amqp method - * - * \since v0.1 - */ -typedef struct amqp_method_t_ { - amqp_method_number_t id; /**< the method id number */ - void *decoded; /**< pointer to the decoded method, - * cast to the appropriate type to use */ -} amqp_method_t; - -/** - * An AMQP frame - * - * \since v0.1 - */ -typedef struct amqp_frame_t_ { - uint8_t frame_type; /**< frame type. The types: - * - AMQP_FRAME_METHOD - use the method union member - * - AMQP_FRAME_HEADER - use the properties union member - * - AMQP_FRAME_BODY - use the body_fragment union member - */ - amqp_channel_t channel; /**< the channel the frame was received on */ - union { - amqp_method_t - method; /**< a method, use if frame_type == AMQP_FRAME_METHOD */ - struct { - uint16_t class_id; /**< the class for the properties */ - uint64_t body_size; /**< size of the body in bytes */ - void *decoded; /**< the decoded properties */ - amqp_bytes_t raw; /**< amqp-encoded properties structure */ - } properties; /**< message header, a.k.a., properties, - use if frame_type == AMQP_FRAME_HEADER */ - amqp_bytes_t body_fragment; /**< a body fragment, use if frame_type == - AMQP_FRAME_BODY */ - struct { - uint8_t transport_high; /**< @internal first byte of handshake */ - uint8_t transport_low; /**< @internal second byte of handshake */ - uint8_t protocol_version_major; /**< @internal third byte of handshake */ - uint8_t protocol_version_minor; /**< @internal fourth byte of handshake */ - } protocol_header; /**< Used only when doing the initial handshake with the - broker, don't use otherwise */ - } payload; /**< the payload of the frame */ -} amqp_frame_t; - -/** - * Response type - * - * \since v0.1 - */ -typedef enum amqp_response_type_enum_ { - AMQP_RESPONSE_NONE = 0, /**< the library got an EOF from the socket */ - AMQP_RESPONSE_NORMAL, /**< response normal, the RPC completed successfully */ - AMQP_RESPONSE_LIBRARY_EXCEPTION, /**< library error, an error occurred in the - library, examine the library_error */ - AMQP_RESPONSE_SERVER_EXCEPTION /**< server exception, the broker returned an - error, check replay */ -} amqp_response_type_enum; - -/** - * Reply from a RPC method on the broker - * - * \since v0.1 - */ -typedef struct amqp_rpc_reply_t_ { - amqp_response_type_enum reply_type; /**< the reply type: - * - AMQP_RESPONSE_NORMAL - the RPC - * completed successfully - * - AMQP_RESPONSE_SERVER_EXCEPTION - the - * broker returned - * an exception, check the reply field - * - AMQP_RESPONSE_LIBRARY_EXCEPTION - the - * library - * encountered an error, check the - * library_error field - */ - amqp_method_t reply; /**< in case of AMQP_RESPONSE_SERVER_EXCEPTION this - * field will be set to the method returned from the - * broker */ - int library_error; /**< in case of AMQP_RESPONSE_LIBRARY_EXCEPTION this - * field will be set to an error code. An error - * string can be retrieved using amqp_error_string */ -} amqp_rpc_reply_t; - -/** - * SASL method type - * - * \since v0.1 - */ -typedef enum amqp_sasl_method_enum_ { - AMQP_SASL_METHOD_UNDEFINED = -1, /**< Invalid SASL method */ - AMQP_SASL_METHOD_PLAIN = - 0, /**< the PLAIN SASL method for authentication to the broker */ - AMQP_SASL_METHOD_EXTERNAL = - 1 /**< the EXTERNAL SASL method for authentication to the broker */ -} amqp_sasl_method_enum; - -/** - * connection state object - * - * \since v0.1 - */ -typedef struct amqp_connection_state_t_ *amqp_connection_state_t; - -/** - * Socket object - * - * \since v0.4.0 - */ -typedef struct amqp_socket_t_ amqp_socket_t; - -/** - * Status codes - * - * \since v0.4.0 - */ -/* NOTE: When updating this enum, update the strings in librabbitmq/amqp_api.c - */ -typedef enum amqp_status_enum_ { - AMQP_STATUS_OK = 0x0, /**< Operation successful */ - AMQP_STATUS_NO_MEMORY = -0x0001, /**< Memory allocation - failed */ - AMQP_STATUS_BAD_AMQP_DATA = -0x0002, /**< Incorrect or corrupt - data was received from - the broker. This is a - protocol error. */ - AMQP_STATUS_UNKNOWN_CLASS = -0x0003, /**< An unknown AMQP class - was received. This is - a protocol error. */ - AMQP_STATUS_UNKNOWN_METHOD = -0x0004, /**< An unknown AMQP method - was received. This is - a protocol error. */ - AMQP_STATUS_HOSTNAME_RESOLUTION_FAILED = -0x0005, /**< Unable to resolve the - * hostname */ - AMQP_STATUS_INCOMPATIBLE_AMQP_VERSION = -0x0006, /**< The broker advertised - an incompaible AMQP - version */ - AMQP_STATUS_CONNECTION_CLOSED = -0x0007, /**< The connection to the - broker has been closed - */ - AMQP_STATUS_BAD_URL = -0x0008, /**< malformed AMQP URL */ - AMQP_STATUS_SOCKET_ERROR = -0x0009, /**< A socket error - occurred */ - AMQP_STATUS_INVALID_PARAMETER = -0x000A, /**< An invalid parameter - was passed into the - function */ - AMQP_STATUS_TABLE_TOO_BIG = -0x000B, /**< The amqp_table_t object - cannot be serialized - because the output - buffer is too small */ - AMQP_STATUS_WRONG_METHOD = -0x000C, /**< The wrong method was - received */ - AMQP_STATUS_TIMEOUT = -0x000D, /**< Operation timed out */ - AMQP_STATUS_TIMER_FAILURE = -0x000E, /**< The underlying system - timer facility failed */ - AMQP_STATUS_HEARTBEAT_TIMEOUT = -0x000F, /**< Timed out waiting for - heartbeat */ - AMQP_STATUS_UNEXPECTED_STATE = -0x0010, /**< Unexpected protocol - state */ - AMQP_STATUS_SOCKET_CLOSED = -0x0011, /**< Underlying socket is - closed */ - AMQP_STATUS_SOCKET_INUSE = -0x0012, /**< Underlying socket is - already open */ - AMQP_STATUS_BROKER_UNSUPPORTED_SASL_METHOD = -0x0013, /**< Broker does not - support the requested - SASL mechanism */ - AMQP_STATUS_UNSUPPORTED = -0x0014, /**< Parameter is unsupported - in this version */ - _AMQP_STATUS_NEXT_VALUE = -0x0015, /**< Internal value */ - - AMQP_STATUS_TCP_ERROR = -0x0100, /**< A generic TCP error - occurred */ - AMQP_STATUS_TCP_SOCKETLIB_INIT_ERROR = -0x0101, /**< An error occurred trying - to initialize the - socket library*/ - _AMQP_STATUS_TCP_NEXT_VALUE = -0x0102, /**< Internal value */ - - AMQP_STATUS_SSL_ERROR = -0x0200, /**< A generic SSL error - occurred. */ - AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED = -0x0201, /**< SSL validation of - hostname against - peer certificate - failed */ - AMQP_STATUS_SSL_PEER_VERIFY_FAILED = -0x0202, /**< SSL validation of peer - certificate failed. */ - AMQP_STATUS_SSL_CONNECTION_FAILED = -0x0203, /**< SSL handshake failed. */ - _AMQP_STATUS_SSL_NEXT_VALUE = -0x0204 /**< Internal value */ -} amqp_status_enum; - -/** - * AMQP delivery modes. - * Use these values for the #amqp_basic_properties_t::delivery_mode field. - * - * \since v0.5 - */ -typedef enum { - AMQP_DELIVERY_NONPERSISTENT = 1, /**< Non-persistent message */ - AMQP_DELIVERY_PERSISTENT = 2 /**< Persistent message */ -} amqp_delivery_mode_enum; - -AMQP_END_DECLS - -#include - -AMQP_BEGIN_DECLS - -/** - * Empty bytes structure - * - * \since v0.2 - */ -AMQP_PUBLIC_VARIABLE const amqp_bytes_t amqp_empty_bytes; - -/** - * Empty table structure - * - * \since v0.2 - */ -AMQP_PUBLIC_VARIABLE const amqp_table_t amqp_empty_table; - -/** - * Empty table array structure - * - * \since v0.2 - */ -AMQP_PUBLIC_VARIABLE const amqp_array_t amqp_empty_array; - -/* Compatibility macros for the above, to avoid the need to update - code written against earlier versions of librabbitmq. */ - -/** - * \def AMQP_EMPTY_BYTES - * - * Deprecated, use \ref amqp_empty_bytes instead - * - * \deprecated use \ref amqp_empty_bytes instead - * - * \since v0.1 - */ -#define AMQP_EMPTY_BYTES amqp_empty_bytes - -/** - * \def AMQP_EMPTY_TABLE - * - * Deprecated, use \ref amqp_empty_table instead - * - * \deprecated use \ref amqp_empty_table instead - * - * \since v0.1 - */ -#define AMQP_EMPTY_TABLE amqp_empty_table - -/** - * \def AMQP_EMPTY_ARRAY - * - * Deprecated, use \ref amqp_empty_array instead - * - * \deprecated use \ref amqp_empty_array instead - * - * \since v0.1 - */ -#define AMQP_EMPTY_ARRAY amqp_empty_array - -/** - * Initializes an amqp_pool_t memory allocation pool for use - * - * Readies an allocation pool for use. An amqp_pool_t - * must be initialized before use - * - * \param [in] pool the amqp_pool_t structure to initialize. - * Calling this function on a pool a pool that has - * already been initialized will result in undefined - * behavior - * \param [in] pagesize the unit size that the pool will allocate - * memory chunks in. Anything allocated against the pool - * with a requested size will be carved out of a block - * this size. Allocations larger than this will be - * allocated individually - * - * \sa recycle_amqp_pool(), empty_amqp_pool(), amqp_pool_alloc(), - * amqp_pool_alloc_bytes(), amqp_pool_t - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL init_amqp_pool(amqp_pool_t *pool, size_t pagesize); - -/** - * Recycles an amqp_pool_t memory allocation pool - * - * Recycles the space allocate by the pool - * - * This invalidates all allocations made against the pool before this call is - * made, any use of any allocations made before recycle_amqp_pool() is called - * will result in undefined behavior. - * - * Note: this may or may not release memory, to force memory to be released - * call empty_amqp_pool(). - * - * \param [in] pool the amqp_pool_t to recycle - * - * \sa recycle_amqp_pool(), empty_amqp_pool(), amqp_pool_alloc(), - * amqp_pool_alloc_bytes() - * - * \since v0.1 - * - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL recycle_amqp_pool(amqp_pool_t *pool); - -/** - * Empties an amqp memory pool - * - * Releases all memory associated with an allocation pool - * - * \param [in] pool the amqp_pool_t to empty - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL empty_amqp_pool(amqp_pool_t *pool); - -/** - * Allocates a block of memory from an amqp_pool_t memory pool - * - * Memory will be aligned on a 8-byte boundary. If a 0-length allocation is - * requested, a NULL pointer will be returned. - * - * \param [in] pool the allocation pool to allocate the memory from - * \param [in] amount the size of the allocation in bytes. - * \return a pointer to the memory block, or NULL if the allocation cannot - * be satisfied. - * - * \sa init_amqp_pool(), recycle_amqp_pool(), empty_amqp_pool(), - * amqp_pool_alloc_bytes() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void *AMQP_CALL amqp_pool_alloc(amqp_pool_t *pool, size_t amount); - -/** - * Allocates a block of memory from an amqp_pool_t to an amqp_bytes_t - * - * Memory will be aligned on a 8-byte boundary. If a 0-length allocation is - * requested, output.bytes = NULL. - * - * \param [in] pool the allocation pool to allocate the memory from - * \param [in] amount the size of the allocation in bytes - * \param [in] output the location to store the pointer. On success - * output.bytes will be set to the beginning of the buffer - * output.len will be set to amount - * On error output.bytes will be set to NULL and output.len - * set to 0 - * - * \sa init_amqp_pool(), recycle_amqp_pool(), empty_amqp_pool(), - * amqp_pool_alloc() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_pool_alloc_bytes(amqp_pool_t *pool, size_t amount, - amqp_bytes_t *output); - -/** - * Wraps a c string in an amqp_bytes_t - * - * Takes a string, calculates its length and creates an - * amqp_bytes_t that points to it. The string is not duplicated. - * - * For a given input cstr, The amqp_bytes_t output.bytes is the - * same as cstr, output.len is the length of the string not including - * the \0 terminator - * - * This function uses strlen() internally so cstr must be properly - * terminated - * - * \param [in] cstr the c string to wrap - * \return an amqp_bytes_t that describes the string - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_bytes_t AMQP_CALL amqp_cstring_bytes(char const *cstr); - -/** - * Duplicates an amqp_bytes_t buffer. - * - * The buffer is cloned and the contents copied. - * - * The memory associated with the output is allocated - * with amqp_bytes_malloc() and should be freed with - * amqp_bytes_free() - * - * \param [in] src - * \return a clone of the src - * - * \sa amqp_bytes_free(), amqp_bytes_malloc() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_bytes_t AMQP_CALL amqp_bytes_malloc_dup(amqp_bytes_t src); - -/** - * Allocates a amqp_bytes_t buffer - * - * Creates an amqp_bytes_t buffer of the specified amount, the buffer should be - * freed using amqp_bytes_free() - * - * \param [in] amount the size of the buffer in bytes - * \returns an amqp_bytes_t with amount bytes allocated. - * output.bytes will be set to NULL on error - * - * \sa amqp_bytes_free(), amqp_bytes_malloc_dup() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_bytes_t AMQP_CALL amqp_bytes_malloc(size_t amount); - -/** - * Frees an amqp_bytes_t buffer - * - * Frees a buffer allocated with amqp_bytes_malloc() or amqp_bytes_malloc_dup() - * - * Calling amqp_bytes_free on buffers not allocated with one - * of those two functions will result in undefined behavior - * - * \param [in] bytes the buffer to free - * - * \sa amqp_bytes_malloc(), amqp_bytes_malloc_dup() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_bytes_free(amqp_bytes_t bytes); - -/** - * Allocate and initialize a new amqp_connection_state_t object - * - * amqp_connection_state_t objects created with this function - * should be freed with amqp_destroy_connection() - * - * \returns an opaque pointer on success, NULL or 0 on failure. - * - * \sa amqp_destroy_connection() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_connection_state_t AMQP_CALL amqp_new_connection(void); - -/** - * Get the underlying socket descriptor for the connection - * - * \warning Use the socket returned from this function carefully, incorrect use - * of the socket outside of the library will lead to undefined behavior. - * Additionally rabbitmq-c may use the socket differently version-to-version, - * what may work in one version, may break in the next version. Be sure to - * throughly test any applications that use the socket returned by this - * function especially when using a newer version of rabbitmq-c - * - * \param [in] state the connection object - * \returns the socket descriptor if one has been set, -1 otherwise - * - * \sa amqp_tcp_socket_new(), amqp_ssl_socket_new(), amqp_socket_open() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_get_sockfd(amqp_connection_state_t state); - -/** - * Deprecated, use amqp_tcp_socket_new() or amqp_ssl_socket_new() - * - * \deprecated Use amqp_tcp_socket_new() or amqp_ssl_socket_new() - * - * Sets the socket descriptor associated with the connection. The socket - * should be connected to a broker, and should not be read to or written from - * before calling this function. A socket descriptor can be created and opened - * using amqp_open_socket() - * - * \param [in] state the connection object - * \param [in] sockfd the socket - * - * \sa amqp_open_socket(), amqp_tcp_socket_new(), amqp_ssl_socket_new() - * - * \since v0.1 - */ -AMQP_DEPRECATED(AMQP_PUBLIC_FUNCTION void AMQP_CALL - amqp_set_sockfd(amqp_connection_state_t state, int sockfd)); - -/** - * Tune client side parameters - * - * \warning This function may call abort() if the connection is in a certain - * state. As such it should probably not be called code outside the library. - * connection parameters should be specified when calling amqp_login() or - * amqp_login_with_properties() - * - * This function changes channel_max, frame_max, and heartbeat parameters, on - * the client side only. It does not try to renegotiate these parameters with - * the broker. Using this function will lead to unexpected results. - * - * \param [in] state the connection object - * \param [in] channel_max the maximum number of channels. - * The largest this can be is 65535 - * \param [in] frame_max the maximum size of an frame. - * The smallest this can be is 4096 - * The largest this can be is 2147483647 - * Unless you know what you're doing the recommended - * size is 131072 or 128KB - * \param [in] heartbeat the number of seconds between heartbeats - * - * \return AMQP_STATUS_OK on success, an amqp_status_enum value otherwise. - * Possible error codes include: - * - AMQP_STATUS_NO_MEMORY memory allocation failed. - * - AMQP_STATUS_TIMER_FAILURE the underlying system timer indicated it - * failed. - * - * \sa amqp_login(), amqp_login_with_properties() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_tune_connection(amqp_connection_state_t state, - int channel_max, int frame_max, - int heartbeat); - -/** - * Get the maximum number of channels the connection can handle - * - * The maximum number of channels is set when connection negotiation takes - * place in amqp_login() or amqp_login_with_properties(). - * - * \param [in] state the connection object - * \return the maximum number of channels. 0 if there is no limit - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_get_channel_max(amqp_connection_state_t state); - -/** - * Get the maximum size of an frame the connection can handle - * - * The maximum size of an frame is set when connection negotiation takes - * place in amqp_login() or amqp_login_with_properties(). - * - * \param [in] state the connection object - * \return the maximum size of an frame. - * - * \since v0.6 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_get_frame_max(amqp_connection_state_t state); - -/** - * Get the number of seconds between heartbeats of the connection - * - * The number of seconds between heartbeats is set when connection - * negotiation takes place in amqp_login() or amqp_login_with_properties(). - * - * \param [in] state the connection object - * \return the number of seconds between heartbeats. - * - * \since v0.6 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_get_heartbeat(amqp_connection_state_t state); - -/** - * Destroys an amqp_connection_state_t object - * - * Destroys a amqp_connection_state_t object that was created with - * amqp_new_connection(). If the connection with the broker is open, it will be - * implicitly closed with a reply code of 200 (success). Any memory that - * would be freed with amqp_maybe_release_buffers() or - * amqp_maybe_release_buffers_on_channel() will be freed, and use of that - * memory will caused undefined behavior. - * - * \param [in] state the connection object - * \return AMQP_STATUS_OK on success. amqp_status_enum value failure - * - * \sa amqp_new_connection() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_destroy_connection(amqp_connection_state_t state); - -/** - * Process incoming data - * - * \warning This is a low-level function intended for those who want to - * have greater control over input and output over the socket from the - * broker. Correctly using this function requires in-depth knowledge of AMQP - * and rabbitmq-c. - * - * For a given buffer of data received from the broker, decode the first - * frame in the buffer. If more than one frame is contained in the input buffer - * the return value will be less than the received_data size, the caller should - * adjust received_data buffer descriptor to point to the beginning of the - * buffer + the return value. - * - * \param [in] state the connection object - * \param [in] received_data a buffer of data received from the broker. The - * function will return the number of bytes of the buffer it used. The - * function copies these bytes to an internal buffer: this part of the buffer - * may be reused after this function successfully completes. - * \param [in,out] decoded_frame caller should pass in a pointer to an - * amqp_frame_t struct. If there is enough data in received_data for a - * complete frame, decoded_frame->frame_type will be set to something OTHER - * than 0. decoded_frame may contain members pointing to memory owned by - * the state object. This memory can be recycled with - * amqp_maybe_release_buffers() or amqp_maybe_release_buffers_on_channel(). - * \return number of bytes consumed from received_data or 0 if a 0-length - * buffer was passed. A negative return value indicates failure. Possible - * errors: - * - AMQP_STATUS_NO_MEMORY failure in allocating memory. The library is likely - * in an indeterminate state making recovery unlikely. Client should note the - * error and terminate the application - * - AMQP_STATUS_BAD_AMQP_DATA bad AMQP data was received. The connection - * should be shutdown immediately - * - AMQP_STATUS_UNKNOWN_METHOD: an unknown method was received from the - * broker. This is likely a protocol error and the connection should be - * shutdown immediately - * - AMQP_STATUS_UNKNOWN_CLASS: a properties frame with an unknown class - * was received from the broker. This is likely a protocol error and the - * connection should be shutdown immediately - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_handle_input(amqp_connection_state_t state, - amqp_bytes_t received_data, - amqp_frame_t *decoded_frame); - -/** - * Check to see if connection memory can be released - * - * \deprecated This function is deprecated in favor of - * amqp_maybe_release_buffers() or amqp_maybe_release_buffers_on_channel() - * - * Checks the state of an amqp_connection_state_t object to see if - * amqp_release_buffers() can be called successfully. - * - * \param [in] state the connection object - * \returns TRUE if the buffers can be released FALSE otherwise - * - * \sa amqp_release_buffers() amqp_maybe_release_buffers() - * amqp_maybe_release_buffers_on_channel() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_boolean_t AMQP_CALL amqp_release_buffers_ok(amqp_connection_state_t state); - -/** - * Release amqp_connection_state_t owned memory - * - * \deprecated This function is deprecated in favor of - * amqp_maybe_release_buffers() or amqp_maybe_release_buffers_on_channel() - * - * \warning caller should ensure amqp_release_buffers_ok() returns true before - * calling this function. Failure to do so may result in abort() being called. - * - * Release memory owned by the amqp_connection_state_t for reuse by the - * library. Use of any memory returned by the library before this function is - * called will result in undefined behavior. - * - * \note internally rabbitmq-c tries to reuse memory when possible. As a result - * its possible calling this function may not have a noticeable effect on - * memory usage. - * - * \param [in] state the connection object - * - * \sa amqp_release_buffers_ok() amqp_maybe_release_buffers() - * amqp_maybe_release_buffers_on_channel() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_release_buffers(amqp_connection_state_t state); - -/** - * Release amqp_connection_state_t owned memory - * - * Release memory owned by the amqp_connection_state_t object related to any - * channel, allowing reuse by the library. Use of any memory returned by the - * library before this function is called with result in undefined behavior. - * - * \note internally rabbitmq-c tries to reuse memory when possible. As a result - * its possible calling this function may not have a noticeable effect on - * memory usage. - * - * \param [in] state the connection object - * - * \sa amqp_maybe_release_buffers_on_channel() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_maybe_release_buffers(amqp_connection_state_t state); - -/** - * Release amqp_connection_state_t owned memory related to a channel - * - * Release memory owned by the amqp_connection_state_t object related to the - * specified channel, allowing reuse by the library. Use of any memory returned - * the library for a specific channel will result in undefined behavior. - * - * \note internally rabbitmq-c tries to reuse memory when possible. As a result - * its possible calling this function may not have a noticeable effect on - * memory usage. - * - * \param [in] state the connection object - * \param [in] channel the channel specifier for which memory should be - * released. Note that the library does not care about the state of the - * channel when calling this function - * - * \sa amqp_maybe_release_buffers() - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_maybe_release_buffers_on_channel( - amqp_connection_state_t state, amqp_channel_t channel); - -/** - * Send a frame to the broker - * - * \param [in] state the connection object - * \param [in] frame the frame to send to the broker - * \return AMQP_STATUS_OK on success, an amqp_status_enum value on error. - * Possible error codes: - * - AMQP_STATUS_BAD_AMQP_DATA the serialized form of the method or - * properties was too large to fit in a single AMQP frame, or the - * method contains an invalid value. The frame was not sent. - * - AMQP_STATUS_TABLE_TOO_BIG the serialized form of an amqp_table_t is - * too large to fit in a single AMQP frame. Frame was not sent. - * - AMQP_STATUS_UNKNOWN_METHOD an invalid method type was passed in - * - AMQP_STATUS_UNKNOWN_CLASS an invalid properties type was passed in - * - AMQP_STATUS_TIMER_FAILURE system timer indicated failure. The frame - * was sent - * - AMQP_STATUS_SOCKET_ERROR - * - AMQP_STATUS_SSL_ERROR - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_send_frame(amqp_connection_state_t state, - amqp_frame_t const *frame); - -/** - * Compare two table entries - * - * Works just like strcmp(), comparing two the table keys, datatype, then values - * - * \param [in] entry1 the entry on the left - * \param [in] entry2 the entry on the right - * \return 0 if entries are equal, 0 < if left is greater, 0 > if right is - * greater - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_table_entry_cmp(void const *entry1, void const *entry2); - -/** - * Open a socket to a remote host - * - * \deprecated This function is deprecated in favor of amqp_socket_open() - * - * Looks up the hostname, then attempts to open a socket to the host using - * the specified portnumber. It also sets various options on the socket to - * improve performance and correctness. - * - * \param [in] hostname this can be a hostname or IP address. - * Both IPv4 and IPv6 are acceptable - * \param [in] portnumber the port to connect on. RabbitMQ brokers - * listen on port 5672, and 5671 for SSL - * \return a positive value indicates success and is the sockfd. A negative - * value (see amqp_status_enum)is returned on failure. Possible error codes: - * - AMQP_STATUS_TCP_SOCKETLIB_INIT_ERROR Initialization of underlying socket - * library failed. - * - AMQP_STATUS_HOSTNAME_RESOLUTION_FAILED hostname lookup failed. - * - AMQP_STATUS_SOCKET_ERROR a socket error occurred. errno or - * WSAGetLastError() may return more useful information. - * - * \note IPv6 support was added in v0.3 - * - * \sa amqp_socket_open() amqp_set_sockfd() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_open_socket(char const *hostname, int portnumber); - -/** - * Send initial AMQP header to the broker - * - * \warning this is a low level function intended for those who want to - * interact with the broker at a very low level. Use of this function without - * understanding what it does will result in AMQP protocol errors. - * - * This function sends the AMQP protocol header to the broker. - * - * \param [in] state the connection object - * \return AMQP_STATUS_OK on success, a negative value on failure. Possible - * error codes: - * - AMQP_STATUS_CONNECTION_CLOSED the connection to the broker was closed. - * - AMQP_STATUS_SOCKET_ERROR a socket error occurred. It is likely the - * underlying socket has been closed. errno or WSAGetLastError() may provide - * further information. - * - AMQP_STATUS_SSL_ERROR a SSL error occurred. The connection to the broker - * was closed. - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_send_header(amqp_connection_state_t state); - -/** - * Checks to see if there are any incoming frames ready to be read - * - * Checks to see if there are any amqp_frame_t objects buffered by the - * amqp_connection_state_t object. Having one or more frames buffered means - * that amqp_simple_wait_frame() or amqp_simple_wait_frame_noblock() will - * return a frame without potentially blocking on a read() call. - * - * \param [in] state the connection object - * \return TRUE if there are frames enqueued, FALSE otherwise - * - * \sa amqp_simple_wait_frame() amqp_simple_wait_frame_noblock() - * amqp_data_in_buffer() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_boolean_t AMQP_CALL amqp_frames_enqueued(amqp_connection_state_t state); - -/** - * Read a single amqp_frame_t - * - * Waits for the next amqp_frame_t frame to be read from the broker. - * This function has the potential to block for a long time in the case of - * waiting for a basic.deliver method frame from the broker. - * - * The library may buffer frames. When an amqp_connection_state_t object - * has frames buffered calling amqp_simple_wait_frame() will return an - * amqp_frame_t without entering a blocking read(). You can test to see if - * an amqp_connection_state_t object has frames buffered by calling the - * amqp_frames_enqueued() function. - * - * The library has a socket read buffer. When there is data in an - * amqp_connection_state_t read buffer, amqp_simple_wait_frame() may return an - * amqp_frame_t without entering a blocking read(). You can test to see if an - * amqp_connection_state_t object has data in its read buffer by calling the - * amqp_data_in_buffer() function. - * - * \param [in] state the connection object - * \param [out] decoded_frame the frame - * \return AMQP_STATUS_OK on success, an amqp_status_enum value - * is returned otherwise. Possible errors include: - * - AMQP_STATUS_NO_MEMORY failure in allocating memory. The library is likely - * in an indeterminate state making recovery unlikely. Client should note the - * error and terminate the application - * - AMQP_STATUS_BAD_AMQP_DATA bad AMQP data was received. The connection - * should be shutdown immediately - * - AMQP_STATUS_UNKNOWN_METHOD: an unknown method was received from the - * broker. This is likely a protocol error and the connection should be - * shutdown immediately - * - AMQP_STATUS_UNKNOWN_CLASS: a properties frame with an unknown class - * was received from the broker. This is likely a protocol error and the - * connection should be shutdown immediately - * - AMQP_STATUS_HEARTBEAT_TIMEOUT timed out while waiting for heartbeat - * from the broker. The connection has been closed. - * - AMQP_STATUS_TIMER_FAILURE system timer indicated failure. - * - AMQP_STATUS_SOCKET_ERROR a socket error occurred. The connection has - * been closed - * - AMQP_STATUS_SSL_ERROR a SSL socket error occurred. The connection has - * been closed. - * - * \sa amqp_simple_wait_frame_noblock() amqp_frames_enqueued() - * amqp_data_in_buffer() - * - * \note as of v0.4.0 this function will no longer return heartbeat frames - * when enabled by specifying a non-zero heartbeat value in amqp_login(). - * Heartbeating is handled internally by the library. - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_simple_wait_frame(amqp_connection_state_t state, - amqp_frame_t *decoded_frame); - -/** - * Read a single amqp_frame_t with a timeout. - * - * Waits for the next amqp_frame_t frame to be read from the broker, up to - * a timespan specified by tv. The function will return AMQP_STATUS_TIMEOUT - * if the timeout is reached. The tv value is not modified by the function. - * - * If a 0 timeval is specified, the function behaves as if its non-blocking: it - * will test to see if a frame can be read from the broker, and return - * immediately. - * - * If NULL is passed in for tv, the function will behave like - * amqp_simple_wait_frame() and block until a frame is received from the broker - * - * The library may buffer frames. When an amqp_connection_state_t object - * has frames buffered calling amqp_simple_wait_frame_noblock() will return an - * amqp_frame_t without entering a blocking read(). You can test to see if an - * amqp_connection_state_t object has frames buffered by calling the - * amqp_frames_enqueued() function. - * - * The library has a socket read buffer. When there is data in an - * amqp_connection_state_t read buffer, amqp_simple_wait_frame_noblock() may - * return - * an amqp_frame_t without entering a blocking read(). You can test to see if an - * amqp_connection_state_t object has data in its read buffer by calling the - * amqp_data_in_buffer() function. - * - * \note This function does not return heartbeat frames. When enabled, - * heartbeating is handed internally internally by the library. - * - * \param [in,out] state the connection object - * \param [out] decoded_frame the frame - * \param [in] tv the maximum time to wait for a frame to be read. Setting - * tv->tv_sec = 0 and tv->tv_usec = 0 will do a non-blocking read. Specifying - * NULL for tv will make the function block until a frame is read. - * \return AMQP_STATUS_OK on success. An amqp_status_enum value is returned - * otherwise. Possible errors include: - * - AMQP_STATUS_TIMEOUT the timeout was reached while waiting for a frame - * from the broker. - * - AMQP_STATUS_INVALID_PARAMETER the tv parameter contains an invalid value. - * - AMQP_STATUS_NO_MEMORY failure in allocating memory. The library is likely - * in an indeterminate state making recovery unlikely. Client should note the - * error and terminate the application - * - AMQP_STATUS_BAD_AMQP_DATA bad AMQP data was received. The connection - * should be shutdown immediately - * - AMQP_STATUS_UNKNOWN_METHOD: an unknown method was received from the - * broker. This is likely a protocol error and the connection should be - * shutdown immediately - * - AMQP_STATUS_UNKNOWN_CLASS: a properties frame with an unknown class - * was received from the broker. This is likely a protocol error and the - * connection should be shutdown immediately - * - AMQP_STATUS_HEARTBEAT_TIMEOUT timed out while waiting for heartbeat - * from the broker. The connection has been closed. - * - AMQP_STATUS_TIMER_FAILURE system timer indicated failure. - * - AMQP_STATUS_SOCKET_ERROR a socket error occurred. The connection has - * been closed - * - AMQP_STATUS_SSL_ERROR a SSL socket error occurred. The connection has - * been closed. - * - * \sa amqp_simple_wait_frame() amqp_frames_enqueued() amqp_data_in_buffer() - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_simple_wait_frame_noblock(amqp_connection_state_t state, - amqp_frame_t *decoded_frame, - struct timeval *tv); - -/** - * Waits for a specific method from the broker - * - * \warning You probably don't want to use this function. If this function - * doesn't receive exactly the frame requested it closes the whole connection. - * - * Waits for a single method on a channel from the broker. - * If a frame is received that does not match expected_channel - * or expected_method the program will abort - * - * \param [in] state the connection object - * \param [in] expected_channel the channel that the method should be delivered - * on - * \param [in] expected_method the method to wait for - * \param [out] output the method - * \returns AMQP_STATUS_OK on success. An amqp_status_enum value is returned - * otherwise. Possible errors include: - * - AMQP_STATUS_WRONG_METHOD a frame containing the wrong method, wrong frame - * type or wrong channel was received. The connection is closed. - * - AMQP_STATUS_NO_MEMORY failure in allocating memory. The library is likely - * in an indeterminate state making recovery unlikely. Client should note the - * error and terminate the application - * - AMQP_STATUS_BAD_AMQP_DATA bad AMQP data was received. The connection - * should be shutdown immediately - * - AMQP_STATUS_UNKNOWN_METHOD: an unknown method was received from the - * broker. This is likely a protocol error and the connection should be - * shutdown immediately - * - AMQP_STATUS_UNKNOWN_CLASS: a properties frame with an unknown class - * was received from the broker. This is likely a protocol error and the - * connection should be shutdown immediately - * - AMQP_STATUS_HEARTBEAT_TIMEOUT timed out while waiting for heartbeat - * from the broker. The connection has been closed. - * - AMQP_STATUS_TIMER_FAILURE system timer indicated failure. - * - AMQP_STATUS_SOCKET_ERROR a socket error occurred. The connection has - * been closed - * - AMQP_STATUS_SSL_ERROR a SSL socket error occurred. The connection has - * been closed. - * - * \since v0.1 - */ - -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_simple_wait_method(amqp_connection_state_t state, - amqp_channel_t expected_channel, - amqp_method_number_t expected_method, - amqp_method_t *output); - -/** - * Sends a method to the broker - * - * This is a thin wrapper around amqp_send_frame(), providing a way to send - * a method to the broker on a specified channel. - * - * \param [in] state the connection object - * \param [in] channel the channel object - * \param [in] id the method number - * \param [in] decoded the method object - * \returns AMQP_STATUS_OK on success, an amqp_status_enum value otherwise. - * Possible errors include: - * - AMQP_STATUS_BAD_AMQP_DATA the serialized form of the method or - * properties was too large to fit in a single AMQP frame, or the - * method contains an invalid value. The frame was not sent. - * - AMQP_STATUS_TABLE_TOO_BIG the serialized form of an amqp_table_t is - * too large to fit in a single AMQP frame. Frame was not sent. - * - AMQP_STATUS_UNKNOWN_METHOD an invalid method type was passed in - * - AMQP_STATUS_UNKNOWN_CLASS an invalid properties type was passed in - * - AMQP_STATUS_TIMER_FAILURE system timer indicated failure. The frame - * was sent - * - AMQP_STATUS_SOCKET_ERROR - * - AMQP_STATUS_SSL_ERROR - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_send_method(amqp_connection_state_t state, - amqp_channel_t channel, amqp_method_number_t id, - void *decoded); - -/** - * Sends a method to the broker and waits for a method response - * - * \param [in] state the connection object - * \param [in] channel the channel object - * \param [in] request_id the method number of the request - * \param [in] expected_reply_ids a 0 terminated array of expected response - * method numbers - * \param [in] decoded_request_method the method to be sent to the broker - * \return a amqp_rpc_reply_t: - * - r.reply_type == AMQP_RESPONSE_NORMAL. RPC completed successfully - * - r.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION. The broker returned an - * exception: - * - If r.reply.id == AMQP_CHANNEL_CLOSE_METHOD a channel exception - * occurred, cast r.reply.decoded to amqp_channel_close_t* to see details - * of the exception. The client should amqp_send_method() a - * amqp_channel_close_ok_t. The channel must be re-opened before it - * can be used again. Any resources associated with the channel - * (auto-delete exchanges, auto-delete queues, consumers) are invalid - * and must be recreated before attempting to use them again. - * - If r.reply.id == AMQP_CONNECTION_CLOSE_METHOD a connection exception - * occurred, cast r.reply.decoded to amqp_connection_close_t* to see - * details of the exception. The client amqp_send_method() a - * amqp_connection_close_ok_t and disconnect from the broker. - * - r.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. An exception occurred - * within the library. Examine r.library_error and compare it against - * amqp_status_enum values to determine the error. - * - * \sa amqp_simple_rpc_decoded() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_simple_rpc( - amqp_connection_state_t state, amqp_channel_t channel, - amqp_method_number_t request_id, amqp_method_number_t *expected_reply_ids, - void *decoded_request_method); - -/** - * Sends a method to the broker and waits for a method response - * - * \param [in] state the connection object - * \param [in] channel the channel object - * \param [in] request_id the method number of the request - * \param [in] reply_id the method number expected in response - * \param [in] decoded_request_method the request method - * \return a pointer to the method returned from the broker, or NULL on error. - * On error amqp_get_rpc_reply() will return an amqp_rpc_reply_t with - * details on the error that occurred. - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -void *AMQP_CALL amqp_simple_rpc_decoded(amqp_connection_state_t state, - amqp_channel_t channel, - amqp_method_number_t request_id, - amqp_method_number_t reply_id, - void *decoded_request_method); - -/** - * Get the last global amqp_rpc_reply - * - * The API methods corresponding to most synchronous AMQP methods - * return a pointer to the decoded method result. Upon error, they - * return NULL, and we need some way of discovering what, if anything, - * went wrong. amqp_get_rpc_reply() returns the most recent - * amqp_rpc_reply_t instance corresponding to such an API operation - * for the given connection. - * - * Only use it for operations that do not themselves return - * amqp_rpc_reply_t; operations that do return amqp_rpc_reply_t - * generally do NOT update this per-connection-global amqp_rpc_reply_t - * instance. - * - * \param [in] state the connection object - * \return the most recent amqp_rpc_reply_t: - * - r.reply_type == AMQP_RESPONSE_NORMAL. RPC completed successfully - * - r.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION. The broker returned an - * exception: - * - If r.reply.id == AMQP_CHANNEL_CLOSE_METHOD a channel exception - * occurred, cast r.reply.decoded to amqp_channel_close_t* to see details - * of the exception. The client should amqp_send_method() a - * amqp_channel_close_ok_t. The channel must be re-opened before it - * can be used again. Any resources associated with the channel - * (auto-delete exchanges, auto-delete queues, consumers) are invalid - * and must be recreated before attempting to use them again. - * - If r.reply.id == AMQP_CONNECTION_CLOSE_METHOD a connection exception - * occurred, cast r.reply.decoded to amqp_connection_close_t* to see - * details of the exception. The client amqp_send_method() a - * amqp_connection_close_ok_t and disconnect from the broker. - * - r.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. An exception occurred - * within the library. Examine r.library_error and compare it against - * amqp_status_enum values to determine the error. - * - * \sa amqp_simple_rpc_decoded() - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_get_rpc_reply(amqp_connection_state_t state); - -/** - * Login to the broker - * - * After using amqp_open_socket and amqp_set_sockfd, call - * amqp_login to complete connecting to the broker - * - * \param [in] state the connection object - * \param [in] vhost the virtual host to connect to on the broker. The default - * on most brokers is "/" - * \param [in] channel_max the limit for number of channels for the connection. - * 0 means no limit, and is a good default - * (AMQP_DEFAULT_MAX_CHANNELS) - * Note that the maximum number of channels the protocol supports - * is 65535 (2^16, with the 0-channel reserved). The server can - * set a lower channel_max and then the client will use the lowest - * of the two - * \param [in] frame_max the maximum size of an AMQP frame on the wire to - * request of the broker for this connection. 4096 is the minimum - * size, 2^31-1 is the maximum, a good default is 131072 (128KB), - * or AMQP_DEFAULT_FRAME_SIZE - * \param [in] heartbeat the number of seconds between heartbeat frames to - * request of the broker. A value of 0 disables heartbeats. - * Note rabbitmq-c only has partial support for heartbeats, as of - * v0.4.0 they are only serviced during amqp_basic_publish() and - * amqp_simple_wait_frame()/amqp_simple_wait_frame_noblock() - * \param [in] sasl_method the SASL method to authenticate with the broker. - * followed by the authentication information. The following SASL - * methods are implemented: - * - AMQP_SASL_METHOD_PLAIN, the AMQP_SASL_METHOD_PLAIN argument - * should be followed by two arguments in this order: - * const char* username, and const char* password. - * - AMQP_SASL_METHOD_EXTERNAL, the AMQP_SASL_METHOD_EXTERNAL - * argument should be followed one argument: - * const char* identity. - * \return amqp_rpc_reply_t indicating success or failure. - * - r.reply_type == AMQP_RESPONSE_NORMAL. Login completed successfully - * - r.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. In most cases errors - * from the broker when logging in will be represented by the broker closing - * the socket. In this case r.library_error will be set to - * AMQP_STATUS_CONNECTION_CLOSED. This error can represent a number of - * error conditions including: invalid vhost, authentication failure. - * - r.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION. The broker returned an - * exception: - * - If r.reply.id == AMQP_CHANNEL_CLOSE_METHOD a channel exception - * occurred, cast r.reply.decoded to amqp_channel_close_t* to see details - * of the exception. The client should amqp_send_method() a - * amqp_channel_close_ok_t. The channel must be re-opened before it - * can be used again. Any resources associated with the channel - * (auto-delete exchanges, auto-delete queues, consumers) are invalid - * and must be recreated before attempting to use them again. - * - If r.reply.id == AMQP_CONNECTION_CLOSE_METHOD a connection exception - * occurred, cast r.reply.decoded to amqp_connection_close_t* to see - * details of the exception. The client amqp_send_method() a - * amqp_connection_close_ok_t and disconnect from the broker. - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_login(amqp_connection_state_t state, - char const *vhost, int channel_max, - int frame_max, int heartbeat, - amqp_sasl_method_enum sasl_method, ...); - -/** - * Login to the broker passing a properties table - * - * This function is similar to amqp_login() and differs in that it provides a - * way to pass client properties to the broker. This is commonly used to - * negotiate newer protocol features as they are supported by the broker. - * - * \param [in] state the connection object - * \param [in] vhost the virtual host to connect to on the broker. The default - * on most brokers is "/" - * \param [in] channel_max the limit for the number of channels for the - * connection. - * 0 means no limit, and is a good default - * (AMQP_DEFAULT_MAX_CHANNELS) - * Note that the maximum number of channels the protocol supports - * is 65535 (2^16, with the 0-channel reserved). The server can - * set a lower channel_max and then the client will use the lowest - * of the two - * \param [in] frame_max the maximum size of an AMQP frame ont he wire to - * request of the broker for this connection. 4096 is the minimum - * size, 2^31-1 is the maximum, a good default is 131072 (128KB), - * or AMQP_DEFAULT_FRAME_SIZE - * \param [in] heartbeat the number of seconds between heartbeat frame to - * request of the broker. A value of 0 disables heartbeats. - * Note rabbitmq-c only has partial support for hearts, as of - * v0.4.0 heartbeats are only serviced during amqp_basic_publish(), - * and amqp_simple_wait_frame()/amqp_simple_wait_frame_noblock() - * \param [in] properties a table of properties to send the broker. - * \param [in] sasl_method the SASL method to authenticate with the broker - * followed by the authentication information. The following SASL - * methods are implemented: - * - AMQP_SASL_METHOD_PLAIN, the AMQP_SASL_METHOD_PLAIN argument - * should be followed by two arguments in this order: - * const char* username, and const char* password. - * - AMQP_SASL_METHOD_EXTERNAL, the AMQP_SASL_METHOD_EXTERNAL - * argument should be followed one argument: - * const char* identity. - * \return amqp_rpc_reply_t indicating success or failure. - * - r.reply_type == AMQP_RESPONSE_NORMAL. Login completed successfully - * - r.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION. In most cases errors - * from the broker when logging in will be represented by the broker closing - * the socket. In this case r.library_error will be set to - * AMQP_STATUS_CONNECTION_CLOSED. This error can represent a number of - * error conditions including: invalid vhost, authentication failure. - * - r.reply_type == AMQP_RESPONSE_SERVER_EXCEPTION. The broker returned an - * exception: - * - If r.reply.id == AMQP_CHANNEL_CLOSE_METHOD a channel exception - * occurred, cast r.reply.decoded to amqp_channel_close_t* to see details - * of the exception. The client should amqp_send_method() a - * amqp_channel_close_ok_t. The channel must be re-opened before it - * can be used again. Any resources associated with the channel - * (auto-delete exchanges, auto-delete queues, consumers) are invalid - * and must be recreated before attempting to use them again. - * - If r.reply.id == AMQP_CONNECTION_CLOSE_METHOD a connection exception - * occurred, cast r.reply.decoded to amqp_connection_close_t* to see - * details of the exception. The client amqp_send_method() a - * amqp_connection_close_ok_t and disconnect from the broker. - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_login_with_properties( - amqp_connection_state_t state, char const *vhost, int channel_max, - int frame_max, int heartbeat, const amqp_table_t *properties, - amqp_sasl_method_enum sasl_method, ...); - -struct amqp_basic_properties_t_; - -/** - * Publish a message to the broker - * - * Publish a message on an exchange with a routing key. - * - * Note that at the AMQ protocol level basic.publish is an async method: - * this means error conditions that occur on the broker (such as publishing to - * a non-existent exchange) will not be reflected in the return value of this - * function. - * - * \param [in] state the connection object - * \param [in] channel the channel identifier - * \param [in] exchange the exchange on the broker to publish to - * \param [in] routing_key the routing key to use when publishing the message - * \param [in] mandatory indicate to the broker that the message MUST be routed - * to a queue. If the broker cannot do this it should respond with - * a basic.return method. - * \param [in] immediate indicate to the broker that the message MUST be - * delivered to a consumer immediately. If the broker cannot do this - * it should respond with a basic.return method. - * \param [in] properties the properties associated with the message - * \param [in] body the message body - * \return AMQP_STATUS_OK on success, amqp_status_enum value on failure. Note - * that basic.publish is an async method, the return value from this - * function only indicates that the message data was successfully - * transmitted to the broker. It does not indicate failures that occur - * on the broker, such as publishing to a non-existent exchange. - * Possible error values: - * - AMQP_STATUS_TIMER_FAILURE: system timer facility returned an error - * the message was not sent. - * - AMQP_STATUS_HEARTBEAT_TIMEOUT: connection timed out waiting for a - * heartbeat from the broker. The message was not sent. - * - AMQP_STATUS_NO_MEMORY: memory allocation failed. The message was - * not sent. - * - AMQP_STATUS_TABLE_TOO_BIG: a table in the properties was too large - * to fit in a single frame. Message was not sent. - * - AMQP_STATUS_CONNECTION_CLOSED: the connection was closed. - * - AMQP_STATUS_SSL_ERROR: a SSL error occurred. - * - AMQP_STATUS_TCP_ERROR: a TCP error occurred. errno or - * WSAGetLastError() may provide more information - * - * Note: this function does heartbeat processing as of v0.4.0 - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_basic_publish( - amqp_connection_state_t state, amqp_channel_t channel, - amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_boolean_t mandatory, - amqp_boolean_t immediate, struct amqp_basic_properties_t_ const *properties, - amqp_bytes_t body); - -/** - * Closes an channel - * - * \param [in] state the connection object - * \param [in] channel the channel identifier - * \param [in] code the reason for closing the channel, AMQP_REPLY_SUCCESS is a - * good default - * \return amqp_rpc_reply_t indicating success or failure - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_channel_close(amqp_connection_state_t state, - amqp_channel_t channel, int code); - -/** - * Closes the entire connection - * - * Implicitly closes all channels and informs the broker the connection - * is being closed, after receiving acknowledgment from the broker it closes - * the socket. - * - * \param [in] state the connection object - * \param [in] code the reason code for closing the connection. - * AMQP_REPLY_SUCCESS is a good default. - * \return amqp_rpc_reply_t indicating the result - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_connection_close(amqp_connection_state_t state, - int code); - -/** - * Acknowledges a message - * - * Does a basic.ack on a received message - * - * \param [in] state the connection object - * \param [in] channel the channel identifier - * \param [in] delivery_tag the delivery tag of the message to be ack'd - * \param [in] multiple if true, ack all messages up to this delivery tag, if - * false ack only this delivery tag - * \return 0 on success, 0 > on failing to send the ack to the broker. - * this will not indicate failure if something goes wrong on the - * broker - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_basic_ack(amqp_connection_state_t state, - amqp_channel_t channel, uint64_t delivery_tag, - amqp_boolean_t multiple); - -/** - * Do a basic.get - * - * Synchonously polls the broker for a message in a queue, and - * retrieves the message if a message is in the queue. - * - * \param [in] state the connection object - * \param [in] channel the channel identifier to use - * \param [in] queue the queue name to retrieve from - * \param [in] no_ack if true the message is automatically ack'ed - * if false amqp_basic_ack should be called once the message - * retrieved has been processed - * \return amqp_rpc_reply indicating success or failure - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_basic_get(amqp_connection_state_t state, - amqp_channel_t channel, - amqp_bytes_t queue, - amqp_boolean_t no_ack); - -/** - * Do a basic.reject - * - * Actively reject a message that has been delivered - * - * \param [in] state the connection object - * \param [in] channel the channel identifier - * \param [in] delivery_tag the delivery tag of the message to reject - * \param [in] requeue indicate to the broker whether it should requeue the - * message or just discard it. - * \return 0 on success, 0 > on failing to send the reject method to the broker. - * This will not indicate failure if something goes wrong on the - * broker. - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_basic_reject(amqp_connection_state_t state, - amqp_channel_t channel, uint64_t delivery_tag, - amqp_boolean_t requeue); - -/** - * Do a basic.nack - * - * Actively reject a message, this has the same effect as amqp_basic_reject() - * however, amqp_basic_nack() can negatively acknowledge multiple messages with - * one call much like amqp_basic_ack() can acknowledge mutliple messages with - * one call. - * - * \param [in] state the connection object - * \param [in] channel the channel identifier - * \param [in] delivery_tag the delivery tag of the message to reject - * \param [in] multiple if set to 1 negatively acknowledge all unacknowledged - * messages on this channel. - * \param [in] requeue indicate to the broker whether it should requeue the - * message or dead-letter it. - * \return AMQP_STATUS_OK on success, an amqp_status_enum value otherwise. - * - * \since v0.5.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_basic_nack(amqp_connection_state_t state, - amqp_channel_t channel, uint64_t delivery_tag, - amqp_boolean_t multiple, amqp_boolean_t requeue); -/** - * Check to see if there is data left in the receive buffer - * - * Can be used to see if there is data still in the buffer, if so - * calling amqp_simple_wait_frame will not immediately enter a - * blocking read. - * - * \param [in] state the connection object - * \return true if there is data in the recieve buffer, false otherwise - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -amqp_boolean_t AMQP_CALL amqp_data_in_buffer(amqp_connection_state_t state); - -/** - * Get the error string for the given error code. - * - * \deprecated This function has been deprecated in favor of - * \ref amqp_error_string2() which returns statically allocated - * string which do not need to be freed by the caller. - * - * The returned string resides on the heap; the caller is responsible - * for freeing it. - * - * \param [in] err return error code - * \return the error string - * - * \since v0.1 - */ -AMQP_DEPRECATED( - AMQP_PUBLIC_FUNCTION char *AMQP_CALL amqp_error_string(int err)); - -/** - * Get the error string for the given error code. - * - * Get an error string associated with an error code. The string is statically - * allocated and does not need to be freed - * - * \param [in] err the error code - * \return the error string - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -const char *AMQP_CALL amqp_error_string2(int err); - -/** - * Deserialize an amqp_table_t from AMQP wireformat - * - * This is an internal function and is not typically used by - * client applications - * - * \param [in] encoded the buffer containing the serialized data - * \param [in] pool memory pool used to allocate the table entries from - * \param [in] output the amqp_table_t structure to fill in. Any existing - * entries will be erased - * \param [in,out] offset The offset into the encoded buffer to start - * reading the serialized table. It will be updated - * by this function to end of the table - * \return AMQP_STATUS_OK on success, an amqp_status_enum value on failure - * Possible error codes: - * - AMQP_STATUS_NO_MEMORY out of memory - * - AMQP_STATUS_BAD_AMQP_DATA invalid wireformat - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_decode_table(amqp_bytes_t encoded, amqp_pool_t *pool, - amqp_table_t *output, size_t *offset); - -/** - * Serializes an amqp_table_t to the AMQP wireformat - * - * This is an internal function and is not typically used by - * client applications - * - * \param [in] encoded the buffer where to serialize the table to - * \param [in] input the amqp_table_t to serialize - * \param [in,out] offset The offset into the encoded buffer to start - * writing the serialized table. It will be updated - * by this function to where writing left off - * \return AMQP_STATUS_OK on success, an amqp_status_enum value on failure - * Possible error codes: - * - AMQP_STATUS_TABLE_TOO_BIG the serialized form is too large for the - * buffer - * - AMQP_STATUS_BAD_AMQP_DATA invalid table - * - * \since v0.1 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_encode_table(amqp_bytes_t encoded, amqp_table_t *input, - size_t *offset); - -/** - * Create a deep-copy of an amqp_table_t object - * - * Creates a deep-copy of an amqp_table_t object, using the provided pool - * object to allocate the necessary memory. This memory can be freed later by - * call recycle_amqp_pool(), or empty_amqp_pool() - * - * \param [in] original the table to copy - * \param [in,out] clone the table to copy to - * \param [in] pool the initialized memory pool to do allocations for the table - * from - * \return AMQP_STATUS_OK on success, amqp_status_enum value on failure. - * Possible error values: - * - AMQP_STATUS_NO_MEMORY - memory allocation failure. - * - AMQP_STATUS_INVALID_PARAMETER - invalid table (e.g., no key name) - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_table_clone(const amqp_table_t *original, - amqp_table_t *clone, amqp_pool_t *pool); - -/** - * A message object - * - * \since v0.4.0 - */ -typedef struct amqp_message_t_ { - amqp_basic_properties_t properties; /**< message properties */ - amqp_bytes_t body; /**< message body */ - amqp_pool_t pool; /**< pool used to allocate properties */ -} amqp_message_t; - -/** - * Reads the next message on a channel - * - * Reads a complete message (header + body) on a specified channel. This - * function is intended to be used with amqp_basic_get() or when an - * AMQP_BASIC_DELIVERY_METHOD method is received. - * - * \param [in,out] state the connection object - * \param [in] channel the channel on which to read the message from - * \param [in,out] message a pointer to a amqp_message_t object. Caller should - * call amqp_message_destroy() when it is done using the - * fields in the message object. The caller is responsible for - * allocating/destroying the amqp_message_t object itself. - * \param [in] flags pass in 0. Currently unused. - * \returns a amqp_rpc_reply_t object. ret.reply_type == AMQP_RESPONSE_NORMAL on - * success. - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_read_message(amqp_connection_state_t state, - amqp_channel_t channel, - amqp_message_t *message, - int flags); - -/** - * Frees memory associated with a amqp_message_t allocated in amqp_read_message - * - * \param [in] message - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_destroy_message(amqp_message_t *message); - -/** - * Envelope object - * - * \since v0.4.0 - */ -typedef struct amqp_envelope_t_ { - amqp_channel_t channel; /**< channel message was delivered on */ - amqp_bytes_t - consumer_tag; /**< the consumer tag the message was delivered to */ - uint64_t delivery_tag; /**< the messages delivery tag */ - amqp_boolean_t redelivered; /**< flag indicating whether this message is being - redelivered */ - amqp_bytes_t exchange; /**< exchange this message was published to */ - amqp_bytes_t - routing_key; /**< the routing key this message was published with */ - amqp_message_t message; /**< the message */ -} amqp_envelope_t; - -/** - * Wait for and consume a message - * - * Waits for a basic.deliver method on any channel, upon receipt of - * basic.deliver it reads that message, and returns. If any other method is - * received before basic.deliver, this function will return an amqp_rpc_reply_t - * with ret.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, and - * ret.library_error == AMQP_STATUS_UNEXPECTED_STATE. The caller should then - * call amqp_simple_wait_frame() to read this frame and take appropriate action. - * - * This function should be used after starting a consumer with the - * amqp_basic_consume() function - * - * \param [in,out] state the connection object - * \param [in,out] envelope a pointer to a amqp_envelope_t object. Caller - * should call #amqp_destroy_envelope() when it is done using - * the fields in the envelope object. The caller is responsible - * for allocating/destroying the amqp_envelope_t object itself. - * \param [in] timeout a timeout to wait for a message delivery. Passing in - * NULL will result in blocking behavior. - * \param [in] flags pass in 0. Currently unused. - * \returns a amqp_rpc_reply_t object. ret.reply_type == AMQP_RESPONSE_NORMAL - * on success. If ret.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION, - * and ret.library_error == AMQP_STATUS_UNEXPECTED_STATE, a frame other - * than AMQP_BASIC_DELIVER_METHOD was received, the caller should call - * amqp_simple_wait_frame() to read this frame and take appropriate - * action. - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_rpc_reply_t AMQP_CALL amqp_consume_message(amqp_connection_state_t state, - amqp_envelope_t *envelope, - struct timeval *timeout, - int flags); - -/** - * Frees memory associated with a amqp_envelope_t allocated in - * amqp_consume_message() - * - * \param [in] envelope - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_destroy_envelope(amqp_envelope_t *envelope); - -/** - * Parameters used to connect to the RabbitMQ broker - * - * \since v0.2 - */ -struct amqp_connection_info { - char *user; /**< the username to authenticate with the broker, default on most - broker is 'guest' */ - char *password; /**< the password to authenticate with the broker, default on - most brokers is 'guest' */ - char *host; /**< the hostname of the broker */ - char *vhost; /**< the virtual host on the broker to connect to, a good default - is "/" */ - int port; /**< the port that the broker is listening on, default on most - brokers is 5672 */ - amqp_boolean_t ssl; -}; - -/** - * Initialze an amqp_connection_info to default values - * - * The default values are: - * - user: "guest" - * - password: "guest" - * - host: "localhost" - * - vhost: "/" - * - port: 5672 - * - * \param [out] parsed the connection info to set defaults on - * - * \since v0.2 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL - amqp_default_connection_info(struct amqp_connection_info *parsed); - -/** - * Parse a connection URL - * - * An amqp connection url takes the form: - * - * amqp://[$USERNAME[:$PASSWORD]\@]$HOST[:$PORT]/[$VHOST] - * - * Examples: - * amqp://guest:guest\@localhost:5672// - * amqp://guest:guest\@localhost/myvhost - * - * Any missing parts of the URL will be set to the defaults specified in - * amqp_default_connection_info. For amqps: URLs the default port will be set - * to 5671 instead of 5672 for non-SSL URLs. - * - * \note This function modifies url parameter. - * - * \param [in] url URI to parse, note that this parameter is modified by the - * function. - * \param [out] parsed the connection info gleaned from the URI. The char* - * members will point to parts of the url input parameter. - * Memory management will depend on how the url is allocated. - * \returns AMQP_STATUS_OK on success, AMQP_STATUS_BAD_URL on failure - * - * \since v0.2 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_parse_url(char *url, struct amqp_connection_info *parsed); - -/* socket API */ - -/** - * Open a socket connection. - * - * This function opens a socket connection returned from amqp_tcp_socket_new() - * or amqp_ssl_socket_new(). This function should be called after setting - * socket options and prior to assigning the socket to an AMQP connection with - * amqp_set_socket(). - * - * \param [in,out] self A socket object. - * \param [in] host Connect to this host. - * \param [in] port Connect on this remote port. - * - * \return AMQP_STATUS_OK on success, an amqp_status_enum on failure - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_socket_open(amqp_socket_t *self, const char *host, int port); - -/** - * Open a socket connection. - * - * This function opens a socket connection returned from amqp_tcp_socket_new() - * or amqp_ssl_socket_new(). This function should be called after setting - * socket options and prior to assigning the socket to an AMQP connection with - * amqp_set_socket(). - * - * \param [in,out] self A socket object. - * \param [in] host Connect to this host. - * \param [in] port Connect on this remote port. - * \param [in] timeout Max allowed time to spent on opening. If NULL - run in - * blocking mode - * - * \return AMQP_STATUS_OK on success, an amqp_status_enum on failure. - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_socket_open_noblock(amqp_socket_t *self, const char *host, - int port, struct timeval *timeout); - -/** - * Get the socket descriptor in use by a socket object. - * - * Retrieve the underlying socket descriptor. This function can be used to - * perform low-level socket operations that aren't supported by the socket - * interface. Use with caution! - * - * \param [in,out] self A socket object. - * - * \return The underlying socket descriptor, or -1 if there is no socket - * descriptor associated with - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_socket_get_sockfd(amqp_socket_t *self); - -/** - * Get the socket object associated with a amqp_connection_state_t - * - * \param [in] state the connection object to get the socket from - * \return a pointer to the socket object, or NULL if one has not been assigned - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_socket_t *AMQP_CALL amqp_get_socket(amqp_connection_state_t state); - -/** - * Get the broker properties table - * - * \param [in] state the connection object - * \return a pointer to an amqp_table_t containing the properties advertised - * by the broker on connection. The connection object owns the table, it - * should not be modified. - * - * \since v0.5.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_table_t *AMQP_CALL - amqp_get_server_properties(amqp_connection_state_t state); - -/** - * Get the client properties table - * - * Get the properties that were passed to the broker on connection. - * - * \param [in] state the connection object - * \return a pointer to an amqp_table_t containing the properties advertised - * by the client on connection. The connection object owns the table, it - * should not be modified. - * - * \since v0.7.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_table_t *AMQP_CALL - amqp_get_client_properties(amqp_connection_state_t state); - -/** - * Get the login handshake timeout. - * - * amqp_login and amqp_login_with_properties perform the login handshake with - * the broker. This function returns the timeout associated with completing - * this operation from the client side. This value can be set by using the - * amqp_set_handshake_timeout. - * - * Note that the RabbitMQ broker has configurable timeout for completing the - * login handshake, the default is 10 seconds. rabbitmq-c has a default of 12 - * seconds. - * - * \param [in] state the connection object - * \return a struct timeval representing the current login timeout for the state - * object. A NULL value represents an infinite timeout. The memory returned is - * owned by the connection object. - * - * \since v0.9.0 - */ -AMQP_PUBLIC_FUNCTION -struct timeval *AMQP_CALL - amqp_get_handshake_timeout(amqp_connection_state_t state); - -/** - * Set the login handshake timeout. - * - * amqp_login and amqp_login_with_properties perform the login handshake with - * the broker. This function sets the timeout associated with completing this - * operation from the client side. - * - * The timeout must be set before amqp_login or amqp_login_with_properties is - * called to change from the default timeout. - * - * Note that the RabbitMQ broker has a configurable timeout for completing the - * login handshake, the default is 10 seconds. rabbitmq-c has a default of 12 - * seconds. - * - * \param [in] state the connection object - * \param [in] timeout a struct timeval* representing new login timeout for the - * state object. NULL represents an infinite timeout. The value of timeout is - * copied internally, the caller is responsible for ownership of the passed in - * pointer, it does not need to remain valid after this function is called. - * \return AMQP_STATUS_OK on success. - * - * \since v0.9.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_set_handshake_timeout(amqp_connection_state_t state, - struct timeval *timeout); - -/** - * Get the RPC timeout - * - * Gets the timeout for any RPC-style AMQP command (e.g., amqp_queue_declare). - * This timeout may be changed at any time by calling \amqp_set_rpc_timeout - * function with a new timeout. The timeout applies individually to each RPC - * that is made. - * - * The default value is NULL, or an infinite timeout. - * - * When an RPC times out, the function will return an error AMQP_STATUS_TIMEOUT, - * and the connection will be closed. - * - *\warning RPC-timeouts are an advanced feature intended to be used to detect - * dead connections quickly when the rabbitmq-c implementation of heartbeats - * does not work. Do not use RPC timeouts unless you understand the implications - * of doing so. - * - * \param [in] state the connection object - * \return a struct timeval representing the current RPC timeout for the state - * object. A NULL value represents an infinite timeout. The memory returned is - * owned by the connection object. - * - * \since v0.9.0 - */ -AMQP_PUBLIC_FUNCTION -struct timeval *AMQP_CALL amqp_get_rpc_timeout(amqp_connection_state_t state); - -/** - * Set the RPC timeout - * - * Sets the timeout for any RPC-style AMQP command (e.g., amqp_queue_declare). - * This timeout may be changed at any time by calling this function with a new - * timeout. The timeout applies individually to each RPC that is made. - * - * The default value is NULL, or an infinite timeout. - * - * When an RPC times out, the function will return an error AMQP_STATUS_TIMEOUT, - * and the connection will be closed. - * - *\warning RPC-timeouts are an advanced feature intended to be used to detect - * dead connections quickly when the rabbitmq-c implementation of heartbeats - * does not work. Do not use RPC timeouts unless you understand the implications - * of doing so. - * - * \param [in] state the connection object - * \param [in] timeout a struct timeval* representing new RPC timeout for the - * state object. NULL represents an infinite timeout. The value of timeout is - * copied internally, the caller is responsible for ownership of the passed - * pointer, it does not need to remain valid after this function is called. - * \return AMQP_STATUS_SUCCESS on success. - * - * \since v0.9.0 - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_set_rpc_timeout(amqp_connection_state_t state, - struct timeval *timeout); - -AMQP_END_DECLS - -#endif /* AMQP_H */ diff --git a/ext/librabbitmq/centos_x64/include/amqp_framing.h b/ext/librabbitmq/centos_x64/include/amqp_framing.h deleted file mode 100644 index fb20acc1..00000000 --- a/ext/librabbitmq/centos_x64/include/amqp_framing.h +++ /dev/null @@ -1,1144 +0,0 @@ -/* Generated code. Do not edit. Edit and re-run codegen.py instead. - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MIT - * - * Portions created by Alan Antonuk are Copyright (c) 2012-2013 - * Alan Antonuk. All Rights Reserved. - * - * Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc. - * All Rights Reserved. - * - * Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010 - * VMware, Inc. and Tony Garnock-Jones. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * ***** END LICENSE BLOCK ***** - */ - -/** @file amqp_framing.h */ -#ifndef AMQP_FRAMING_H -#define AMQP_FRAMING_H - -#include - -AMQP_BEGIN_DECLS - -#define AMQP_PROTOCOL_VERSION_MAJOR 0 /**< AMQP protocol version major */ -#define AMQP_PROTOCOL_VERSION_MINOR 9 /**< AMQP protocol version minor */ -#define AMQP_PROTOCOL_VERSION_REVISION \ - 1 /**< AMQP protocol version revision \ - */ -#define AMQP_PROTOCOL_PORT 5672 /**< Default AMQP Port */ -#define AMQP_FRAME_METHOD 1 /**< Constant: FRAME-METHOD */ -#define AMQP_FRAME_HEADER 2 /**< Constant: FRAME-HEADER */ -#define AMQP_FRAME_BODY 3 /**< Constant: FRAME-BODY */ -#define AMQP_FRAME_HEARTBEAT 8 /**< Constant: FRAME-HEARTBEAT */ -#define AMQP_FRAME_MIN_SIZE 4096 /**< Constant: FRAME-MIN-SIZE */ -#define AMQP_FRAME_END 206 /**< Constant: FRAME-END */ -#define AMQP_REPLY_SUCCESS 200 /**< Constant: REPLY-SUCCESS */ -#define AMQP_CONTENT_TOO_LARGE 311 /**< Constant: CONTENT-TOO-LARGE */ -#define AMQP_NO_ROUTE 312 /**< Constant: NO-ROUTE */ -#define AMQP_NO_CONSUMERS 313 /**< Constant: NO-CONSUMERS */ -#define AMQP_ACCESS_REFUSED 403 /**< Constant: ACCESS-REFUSED */ -#define AMQP_NOT_FOUND 404 /**< Constant: NOT-FOUND */ -#define AMQP_RESOURCE_LOCKED 405 /**< Constant: RESOURCE-LOCKED */ -#define AMQP_PRECONDITION_FAILED 406 /**< Constant: PRECONDITION-FAILED */ -#define AMQP_CONNECTION_FORCED 320 /**< Constant: CONNECTION-FORCED */ -#define AMQP_INVALID_PATH 402 /**< Constant: INVALID-PATH */ -#define AMQP_FRAME_ERROR 501 /**< Constant: FRAME-ERROR */ -#define AMQP_SYNTAX_ERROR 502 /**< Constant: SYNTAX-ERROR */ -#define AMQP_COMMAND_INVALID 503 /**< Constant: COMMAND-INVALID */ -#define AMQP_CHANNEL_ERROR 504 /**< Constant: CHANNEL-ERROR */ -#define AMQP_UNEXPECTED_FRAME 505 /**< Constant: UNEXPECTED-FRAME */ -#define AMQP_RESOURCE_ERROR 506 /**< Constant: RESOURCE-ERROR */ -#define AMQP_NOT_ALLOWED 530 /**< Constant: NOT-ALLOWED */ -#define AMQP_NOT_IMPLEMENTED 540 /**< Constant: NOT-IMPLEMENTED */ -#define AMQP_INTERNAL_ERROR 541 /**< Constant: INTERNAL-ERROR */ - -/* Function prototypes. */ - -/** - * Get constant name string from constant - * - * @param [in] constantNumber constant to get the name of - * @returns string describing the constant. String is managed by - * the library and should not be free()'d by the program - */ -AMQP_PUBLIC_FUNCTION -char const *AMQP_CALL amqp_constant_name(int constantNumber); - -/** - * Checks to see if a constant is a hard error - * - * A hard error occurs when something severe enough - * happens that the connection must be closed. - * - * @param [in] constantNumber the error constant - * @returns true if its a hard error, false otherwise - */ -AMQP_PUBLIC_FUNCTION -amqp_boolean_t AMQP_CALL amqp_constant_is_hard_error(int constantNumber); - -/** - * Get method name string from method number - * - * @param [in] methodNumber the method number - * @returns method name string. String is managed by the library - * and should not be freed()'d by the program - */ -AMQP_PUBLIC_FUNCTION -char const *AMQP_CALL amqp_method_name(amqp_method_number_t methodNumber); - -/** - * Check whether a method has content - * - * A method that has content will receive the method frame - * a properties frame, then 1 to N body frames - * - * @param [in] methodNumber the method number - * @returns true if method has content, false otherwise - */ -AMQP_PUBLIC_FUNCTION -amqp_boolean_t AMQP_CALL - amqp_method_has_content(amqp_method_number_t methodNumber); - -/** - * Decodes a method from AMQP wireformat - * - * @param [in] methodNumber the method number for the decoded parameter - * @param [in] pool the memory pool to allocate the decoded method from - * @param [in] encoded the encoded byte string buffer - * @param [out] decoded pointer to the decoded method struct - * @returns 0 on success, an error code otherwise - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_decode_method(amqp_method_number_t methodNumber, - amqp_pool_t *pool, amqp_bytes_t encoded, - void **decoded); - -/** - * Decodes a header frame properties structure from AMQP wireformat - * - * @param [in] class_id the class id for the decoded parameter - * @param [in] pool the memory pool to allocate the decoded properties from - * @param [in] encoded the encoded byte string buffer - * @param [out] decoded pointer to the decoded properties struct - * @returns 0 on success, an error code otherwise - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_decode_properties(uint16_t class_id, amqp_pool_t *pool, - amqp_bytes_t encoded, void **decoded); - -/** - * Encodes a method structure in AMQP wireformat - * - * @param [in] methodNumber the method number for the decoded parameter - * @param [in] decoded the method structure (e.g., amqp_connection_start_t) - * @param [in] encoded an allocated byte buffer for the encoded method - * structure to be written to. If the buffer isn't large enough - * to hold the encoded method, an error code will be returned. - * @returns 0 on success, an error code otherwise. - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_encode_method(amqp_method_number_t methodNumber, - void *decoded, amqp_bytes_t encoded); - -/** - * Encodes a properties structure in AMQP wireformat - * - * @param [in] class_id the class id for the decoded parameter - * @param [in] decoded the properties structure (e.g., amqp_basic_properties_t) - * @param [in] encoded an allocated byte buffer for the encoded properties to - * written to. - * If the buffer isn't large enough to hold the encoded method, an - * an error code will be returned - * @returns 0 on success, an error code otherwise. - */ -AMQP_PUBLIC_FUNCTION -int AMQP_CALL amqp_encode_properties(uint16_t class_id, void *decoded, - amqp_bytes_t encoded); - -/* Method field records. */ - -#define AMQP_CONNECTION_START_METHOD \ - ((amqp_method_number_t)0x000A000A) /**< connection.start method id \ - @internal 10, 10; 655370 */ -/** connection.start method fields */ -typedef struct amqp_connection_start_t_ { - uint8_t version_major; /**< version-major */ - uint8_t version_minor; /**< version-minor */ - amqp_table_t server_properties; /**< server-properties */ - amqp_bytes_t mechanisms; /**< mechanisms */ - amqp_bytes_t locales; /**< locales */ -} amqp_connection_start_t; - -#define AMQP_CONNECTION_START_OK_METHOD \ - ((amqp_method_number_t)0x000A000B) /**< connection.start-ok method id \ - @internal 10, 11; 655371 */ -/** connection.start-ok method fields */ -typedef struct amqp_connection_start_ok_t_ { - amqp_table_t client_properties; /**< client-properties */ - amqp_bytes_t mechanism; /**< mechanism */ - amqp_bytes_t response; /**< response */ - amqp_bytes_t locale; /**< locale */ -} amqp_connection_start_ok_t; - -#define AMQP_CONNECTION_SECURE_METHOD \ - ((amqp_method_number_t)0x000A0014) /**< connection.secure method id \ - @internal 10, 20; 655380 */ -/** connection.secure method fields */ -typedef struct amqp_connection_secure_t_ { - amqp_bytes_t challenge; /**< challenge */ -} amqp_connection_secure_t; - -#define AMQP_CONNECTION_SECURE_OK_METHOD \ - ((amqp_method_number_t)0x000A0015) /**< connection.secure-ok method id \ - @internal 10, 21; 655381 */ -/** connection.secure-ok method fields */ -typedef struct amqp_connection_secure_ok_t_ { - amqp_bytes_t response; /**< response */ -} amqp_connection_secure_ok_t; - -#define AMQP_CONNECTION_TUNE_METHOD \ - ((amqp_method_number_t)0x000A001E) /**< connection.tune method id \ - @internal 10, 30; 655390 */ -/** connection.tune method fields */ -typedef struct amqp_connection_tune_t_ { - uint16_t channel_max; /**< channel-max */ - uint32_t frame_max; /**< frame-max */ - uint16_t heartbeat; /**< heartbeat */ -} amqp_connection_tune_t; - -#define AMQP_CONNECTION_TUNE_OK_METHOD \ - ((amqp_method_number_t)0x000A001F) /**< connection.tune-ok method id \ - @internal 10, 31; 655391 */ -/** connection.tune-ok method fields */ -typedef struct amqp_connection_tune_ok_t_ { - uint16_t channel_max; /**< channel-max */ - uint32_t frame_max; /**< frame-max */ - uint16_t heartbeat; /**< heartbeat */ -} amqp_connection_tune_ok_t; - -#define AMQP_CONNECTION_OPEN_METHOD \ - ((amqp_method_number_t)0x000A0028) /**< connection.open method id \ - @internal 10, 40; 655400 */ -/** connection.open method fields */ -typedef struct amqp_connection_open_t_ { - amqp_bytes_t virtual_host; /**< virtual-host */ - amqp_bytes_t capabilities; /**< capabilities */ - amqp_boolean_t insist; /**< insist */ -} amqp_connection_open_t; - -#define AMQP_CONNECTION_OPEN_OK_METHOD \ - ((amqp_method_number_t)0x000A0029) /**< connection.open-ok method id \ - @internal 10, 41; 655401 */ -/** connection.open-ok method fields */ -typedef struct amqp_connection_open_ok_t_ { - amqp_bytes_t known_hosts; /**< known-hosts */ -} amqp_connection_open_ok_t; - -#define AMQP_CONNECTION_CLOSE_METHOD \ - ((amqp_method_number_t)0x000A0032) /**< connection.close method id \ - @internal 10, 50; 655410 */ -/** connection.close method fields */ -typedef struct amqp_connection_close_t_ { - uint16_t reply_code; /**< reply-code */ - amqp_bytes_t reply_text; /**< reply-text */ - uint16_t class_id; /**< class-id */ - uint16_t method_id; /**< method-id */ -} amqp_connection_close_t; - -#define AMQP_CONNECTION_CLOSE_OK_METHOD \ - ((amqp_method_number_t)0x000A0033) /**< connection.close-ok method id \ - @internal 10, 51; 655411 */ -/** connection.close-ok method fields */ -typedef struct amqp_connection_close_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_connection_close_ok_t; - -#define AMQP_CONNECTION_BLOCKED_METHOD \ - ((amqp_method_number_t)0x000A003C) /**< connection.blocked method id \ - @internal 10, 60; 655420 */ -/** connection.blocked method fields */ -typedef struct amqp_connection_blocked_t_ { - amqp_bytes_t reason; /**< reason */ -} amqp_connection_blocked_t; - -#define AMQP_CONNECTION_UNBLOCKED_METHOD \ - ((amqp_method_number_t)0x000A003D) /**< connection.unblocked method id \ - @internal 10, 61; 655421 */ -/** connection.unblocked method fields */ -typedef struct amqp_connection_unblocked_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_connection_unblocked_t; - -#define AMQP_CHANNEL_OPEN_METHOD \ - ((amqp_method_number_t)0x0014000A) /**< channel.open method id @internal \ - 20, 10; 1310730 */ -/** channel.open method fields */ -typedef struct amqp_channel_open_t_ { - amqp_bytes_t out_of_band; /**< out-of-band */ -} amqp_channel_open_t; - -#define AMQP_CHANNEL_OPEN_OK_METHOD \ - ((amqp_method_number_t)0x0014000B) /**< channel.open-ok method id \ - @internal 20, 11; 1310731 */ -/** channel.open-ok method fields */ -typedef struct amqp_channel_open_ok_t_ { - amqp_bytes_t channel_id; /**< channel-id */ -} amqp_channel_open_ok_t; - -#define AMQP_CHANNEL_FLOW_METHOD \ - ((amqp_method_number_t)0x00140014) /**< channel.flow method id @internal \ - 20, 20; 1310740 */ -/** channel.flow method fields */ -typedef struct amqp_channel_flow_t_ { - amqp_boolean_t active; /**< active */ -} amqp_channel_flow_t; - -#define AMQP_CHANNEL_FLOW_OK_METHOD \ - ((amqp_method_number_t)0x00140015) /**< channel.flow-ok method id \ - @internal 20, 21; 1310741 */ -/** channel.flow-ok method fields */ -typedef struct amqp_channel_flow_ok_t_ { - amqp_boolean_t active; /**< active */ -} amqp_channel_flow_ok_t; - -#define AMQP_CHANNEL_CLOSE_METHOD \ - ((amqp_method_number_t)0x00140028) /**< channel.close method id @internal \ - 20, 40; 1310760 */ -/** channel.close method fields */ -typedef struct amqp_channel_close_t_ { - uint16_t reply_code; /**< reply-code */ - amqp_bytes_t reply_text; /**< reply-text */ - uint16_t class_id; /**< class-id */ - uint16_t method_id; /**< method-id */ -} amqp_channel_close_t; - -#define AMQP_CHANNEL_CLOSE_OK_METHOD \ - ((amqp_method_number_t)0x00140029) /**< channel.close-ok method id \ - @internal 20, 41; 1310761 */ -/** channel.close-ok method fields */ -typedef struct amqp_channel_close_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_channel_close_ok_t; - -#define AMQP_ACCESS_REQUEST_METHOD \ - ((amqp_method_number_t)0x001E000A) /**< access.request method id @internal \ - 30, 10; 1966090 */ -/** access.request method fields */ -typedef struct amqp_access_request_t_ { - amqp_bytes_t realm; /**< realm */ - amqp_boolean_t exclusive; /**< exclusive */ - amqp_boolean_t passive; /**< passive */ - amqp_boolean_t active; /**< active */ - amqp_boolean_t write; /**< write */ - amqp_boolean_t read; /**< read */ -} amqp_access_request_t; - -#define AMQP_ACCESS_REQUEST_OK_METHOD \ - ((amqp_method_number_t)0x001E000B) /**< access.request-ok method id \ - @internal 30, 11; 1966091 */ -/** access.request-ok method fields */ -typedef struct amqp_access_request_ok_t_ { - uint16_t ticket; /**< ticket */ -} amqp_access_request_ok_t; - -#define AMQP_EXCHANGE_DECLARE_METHOD \ - ((amqp_method_number_t)0x0028000A) /**< exchange.declare method id \ - @internal 40, 10; 2621450 */ -/** exchange.declare method fields */ -typedef struct amqp_exchange_declare_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t type; /**< type */ - amqp_boolean_t passive; /**< passive */ - amqp_boolean_t durable; /**< durable */ - amqp_boolean_t auto_delete; /**< auto-delete */ - amqp_boolean_t internal; /**< internal */ - amqp_boolean_t nowait; /**< nowait */ - amqp_table_t arguments; /**< arguments */ -} amqp_exchange_declare_t; - -#define AMQP_EXCHANGE_DECLARE_OK_METHOD \ - ((amqp_method_number_t)0x0028000B) /**< exchange.declare-ok method id \ - @internal 40, 11; 2621451 */ -/** exchange.declare-ok method fields */ -typedef struct amqp_exchange_declare_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_exchange_declare_ok_t; - -#define AMQP_EXCHANGE_DELETE_METHOD \ - ((amqp_method_number_t)0x00280014) /**< exchange.delete method id \ - @internal 40, 20; 2621460 */ -/** exchange.delete method fields */ -typedef struct amqp_exchange_delete_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t exchange; /**< exchange */ - amqp_boolean_t if_unused; /**< if-unused */ - amqp_boolean_t nowait; /**< nowait */ -} amqp_exchange_delete_t; - -#define AMQP_EXCHANGE_DELETE_OK_METHOD \ - ((amqp_method_number_t)0x00280015) /**< exchange.delete-ok method id \ - @internal 40, 21; 2621461 */ -/** exchange.delete-ok method fields */ -typedef struct amqp_exchange_delete_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_exchange_delete_ok_t; - -#define AMQP_EXCHANGE_BIND_METHOD \ - ((amqp_method_number_t)0x0028001E) /**< exchange.bind method id @internal \ - 40, 30; 2621470 */ -/** exchange.bind method fields */ -typedef struct amqp_exchange_bind_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t destination; /**< destination */ - amqp_bytes_t source; /**< source */ - amqp_bytes_t routing_key; /**< routing-key */ - amqp_boolean_t nowait; /**< nowait */ - amqp_table_t arguments; /**< arguments */ -} amqp_exchange_bind_t; - -#define AMQP_EXCHANGE_BIND_OK_METHOD \ - ((amqp_method_number_t)0x0028001F) /**< exchange.bind-ok method id \ - @internal 40, 31; 2621471 */ -/** exchange.bind-ok method fields */ -typedef struct amqp_exchange_bind_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_exchange_bind_ok_t; - -#define AMQP_EXCHANGE_UNBIND_METHOD \ - ((amqp_method_number_t)0x00280028) /**< exchange.unbind method id \ - @internal 40, 40; 2621480 */ -/** exchange.unbind method fields */ -typedef struct amqp_exchange_unbind_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t destination; /**< destination */ - amqp_bytes_t source; /**< source */ - amqp_bytes_t routing_key; /**< routing-key */ - amqp_boolean_t nowait; /**< nowait */ - amqp_table_t arguments; /**< arguments */ -} amqp_exchange_unbind_t; - -#define AMQP_EXCHANGE_UNBIND_OK_METHOD \ - ((amqp_method_number_t)0x00280033) /**< exchange.unbind-ok method id \ - @internal 40, 51; 2621491 */ -/** exchange.unbind-ok method fields */ -typedef struct amqp_exchange_unbind_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_exchange_unbind_ok_t; - -#define AMQP_QUEUE_DECLARE_METHOD \ - ((amqp_method_number_t)0x0032000A) /**< queue.declare method id @internal \ - 50, 10; 3276810 */ -/** queue.declare method fields */ -typedef struct amqp_queue_declare_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_boolean_t passive; /**< passive */ - amqp_boolean_t durable; /**< durable */ - amqp_boolean_t exclusive; /**< exclusive */ - amqp_boolean_t auto_delete; /**< auto-delete */ - amqp_boolean_t nowait; /**< nowait */ - amqp_table_t arguments; /**< arguments */ -} amqp_queue_declare_t; - -#define AMQP_QUEUE_DECLARE_OK_METHOD \ - ((amqp_method_number_t)0x0032000B) /**< queue.declare-ok method id \ - @internal 50, 11; 3276811 */ -/** queue.declare-ok method fields */ -typedef struct amqp_queue_declare_ok_t_ { - amqp_bytes_t queue; /**< queue */ - uint32_t message_count; /**< message-count */ - uint32_t consumer_count; /**< consumer-count */ -} amqp_queue_declare_ok_t; - -#define AMQP_QUEUE_BIND_METHOD \ - ((amqp_method_number_t)0x00320014) /**< queue.bind method id @internal 50, \ - 20; 3276820 */ -/** queue.bind method fields */ -typedef struct amqp_queue_bind_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t routing_key; /**< routing-key */ - amqp_boolean_t nowait; /**< nowait */ - amqp_table_t arguments; /**< arguments */ -} amqp_queue_bind_t; - -#define AMQP_QUEUE_BIND_OK_METHOD \ - ((amqp_method_number_t)0x00320015) /**< queue.bind-ok method id @internal \ - 50, 21; 3276821 */ -/** queue.bind-ok method fields */ -typedef struct amqp_queue_bind_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_queue_bind_ok_t; - -#define AMQP_QUEUE_PURGE_METHOD \ - ((amqp_method_number_t)0x0032001E) /**< queue.purge method id @internal \ - 50, 30; 3276830 */ -/** queue.purge method fields */ -typedef struct amqp_queue_purge_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_boolean_t nowait; /**< nowait */ -} amqp_queue_purge_t; - -#define AMQP_QUEUE_PURGE_OK_METHOD \ - ((amqp_method_number_t)0x0032001F) /**< queue.purge-ok method id @internal \ - 50, 31; 3276831 */ -/** queue.purge-ok method fields */ -typedef struct amqp_queue_purge_ok_t_ { - uint32_t message_count; /**< message-count */ -} amqp_queue_purge_ok_t; - -#define AMQP_QUEUE_DELETE_METHOD \ - ((amqp_method_number_t)0x00320028) /**< queue.delete method id @internal \ - 50, 40; 3276840 */ -/** queue.delete method fields */ -typedef struct amqp_queue_delete_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_boolean_t if_unused; /**< if-unused */ - amqp_boolean_t if_empty; /**< if-empty */ - amqp_boolean_t nowait; /**< nowait */ -} amqp_queue_delete_t; - -#define AMQP_QUEUE_DELETE_OK_METHOD \ - ((amqp_method_number_t)0x00320029) /**< queue.delete-ok method id \ - @internal 50, 41; 3276841 */ -/** queue.delete-ok method fields */ -typedef struct amqp_queue_delete_ok_t_ { - uint32_t message_count; /**< message-count */ -} amqp_queue_delete_ok_t; - -#define AMQP_QUEUE_UNBIND_METHOD \ - ((amqp_method_number_t)0x00320032) /**< queue.unbind method id @internal \ - 50, 50; 3276850 */ -/** queue.unbind method fields */ -typedef struct amqp_queue_unbind_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t routing_key; /**< routing-key */ - amqp_table_t arguments; /**< arguments */ -} amqp_queue_unbind_t; - -#define AMQP_QUEUE_UNBIND_OK_METHOD \ - ((amqp_method_number_t)0x00320033) /**< queue.unbind-ok method id \ - @internal 50, 51; 3276851 */ -/** queue.unbind-ok method fields */ -typedef struct amqp_queue_unbind_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_queue_unbind_ok_t; - -#define AMQP_BASIC_QOS_METHOD \ - ((amqp_method_number_t)0x003C000A) /**< basic.qos method id @internal 60, \ - 10; 3932170 */ -/** basic.qos method fields */ -typedef struct amqp_basic_qos_t_ { - uint32_t prefetch_size; /**< prefetch-size */ - uint16_t prefetch_count; /**< prefetch-count */ - amqp_boolean_t global; /**< global */ -} amqp_basic_qos_t; - -#define AMQP_BASIC_QOS_OK_METHOD \ - ((amqp_method_number_t)0x003C000B) /**< basic.qos-ok method id @internal \ - 60, 11; 3932171 */ -/** basic.qos-ok method fields */ -typedef struct amqp_basic_qos_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_basic_qos_ok_t; - -#define AMQP_BASIC_CONSUME_METHOD \ - ((amqp_method_number_t)0x003C0014) /**< basic.consume method id @internal \ - 60, 20; 3932180 */ -/** basic.consume method fields */ -typedef struct amqp_basic_consume_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_bytes_t consumer_tag; /**< consumer-tag */ - amqp_boolean_t no_local; /**< no-local */ - amqp_boolean_t no_ack; /**< no-ack */ - amqp_boolean_t exclusive; /**< exclusive */ - amqp_boolean_t nowait; /**< nowait */ - amqp_table_t arguments; /**< arguments */ -} amqp_basic_consume_t; - -#define AMQP_BASIC_CONSUME_OK_METHOD \ - ((amqp_method_number_t)0x003C0015) /**< basic.consume-ok method id \ - @internal 60, 21; 3932181 */ -/** basic.consume-ok method fields */ -typedef struct amqp_basic_consume_ok_t_ { - amqp_bytes_t consumer_tag; /**< consumer-tag */ -} amqp_basic_consume_ok_t; - -#define AMQP_BASIC_CANCEL_METHOD \ - ((amqp_method_number_t)0x003C001E) /**< basic.cancel method id @internal \ - 60, 30; 3932190 */ -/** basic.cancel method fields */ -typedef struct amqp_basic_cancel_t_ { - amqp_bytes_t consumer_tag; /**< consumer-tag */ - amqp_boolean_t nowait; /**< nowait */ -} amqp_basic_cancel_t; - -#define AMQP_BASIC_CANCEL_OK_METHOD \ - ((amqp_method_number_t)0x003C001F) /**< basic.cancel-ok method id \ - @internal 60, 31; 3932191 */ -/** basic.cancel-ok method fields */ -typedef struct amqp_basic_cancel_ok_t_ { - amqp_bytes_t consumer_tag; /**< consumer-tag */ -} amqp_basic_cancel_ok_t; - -#define AMQP_BASIC_PUBLISH_METHOD \ - ((amqp_method_number_t)0x003C0028) /**< basic.publish method id @internal \ - 60, 40; 3932200 */ -/** basic.publish method fields */ -typedef struct amqp_basic_publish_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t routing_key; /**< routing-key */ - amqp_boolean_t mandatory; /**< mandatory */ - amqp_boolean_t immediate; /**< immediate */ -} amqp_basic_publish_t; - -#define AMQP_BASIC_RETURN_METHOD \ - ((amqp_method_number_t)0x003C0032) /**< basic.return method id @internal \ - 60, 50; 3932210 */ -/** basic.return method fields */ -typedef struct amqp_basic_return_t_ { - uint16_t reply_code; /**< reply-code */ - amqp_bytes_t reply_text; /**< reply-text */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t routing_key; /**< routing-key */ -} amqp_basic_return_t; - -#define AMQP_BASIC_DELIVER_METHOD \ - ((amqp_method_number_t)0x003C003C) /**< basic.deliver method id @internal \ - 60, 60; 3932220 */ -/** basic.deliver method fields */ -typedef struct amqp_basic_deliver_t_ { - amqp_bytes_t consumer_tag; /**< consumer-tag */ - uint64_t delivery_tag; /**< delivery-tag */ - amqp_boolean_t redelivered; /**< redelivered */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t routing_key; /**< routing-key */ -} amqp_basic_deliver_t; - -#define AMQP_BASIC_GET_METHOD \ - ((amqp_method_number_t)0x003C0046) /**< basic.get method id @internal 60, \ - 70; 3932230 */ -/** basic.get method fields */ -typedef struct amqp_basic_get_t_ { - uint16_t ticket; /**< ticket */ - amqp_bytes_t queue; /**< queue */ - amqp_boolean_t no_ack; /**< no-ack */ -} amqp_basic_get_t; - -#define AMQP_BASIC_GET_OK_METHOD \ - ((amqp_method_number_t)0x003C0047) /**< basic.get-ok method id @internal \ - 60, 71; 3932231 */ -/** basic.get-ok method fields */ -typedef struct amqp_basic_get_ok_t_ { - uint64_t delivery_tag; /**< delivery-tag */ - amqp_boolean_t redelivered; /**< redelivered */ - amqp_bytes_t exchange; /**< exchange */ - amqp_bytes_t routing_key; /**< routing-key */ - uint32_t message_count; /**< message-count */ -} amqp_basic_get_ok_t; - -#define AMQP_BASIC_GET_EMPTY_METHOD \ - ((amqp_method_number_t)0x003C0048) /**< basic.get-empty method id \ - @internal 60, 72; 3932232 */ -/** basic.get-empty method fields */ -typedef struct amqp_basic_get_empty_t_ { - amqp_bytes_t cluster_id; /**< cluster-id */ -} amqp_basic_get_empty_t; - -#define AMQP_BASIC_ACK_METHOD \ - ((amqp_method_number_t)0x003C0050) /**< basic.ack method id @internal 60, \ - 80; 3932240 */ -/** basic.ack method fields */ -typedef struct amqp_basic_ack_t_ { - uint64_t delivery_tag; /**< delivery-tag */ - amqp_boolean_t multiple; /**< multiple */ -} amqp_basic_ack_t; - -#define AMQP_BASIC_REJECT_METHOD \ - ((amqp_method_number_t)0x003C005A) /**< basic.reject method id @internal \ - 60, 90; 3932250 */ -/** basic.reject method fields */ -typedef struct amqp_basic_reject_t_ { - uint64_t delivery_tag; /**< delivery-tag */ - amqp_boolean_t requeue; /**< requeue */ -} amqp_basic_reject_t; - -#define AMQP_BASIC_RECOVER_ASYNC_METHOD \ - ((amqp_method_number_t)0x003C0064) /**< basic.recover-async method id \ - @internal 60, 100; 3932260 */ -/** basic.recover-async method fields */ -typedef struct amqp_basic_recover_async_t_ { - amqp_boolean_t requeue; /**< requeue */ -} amqp_basic_recover_async_t; - -#define AMQP_BASIC_RECOVER_METHOD \ - ((amqp_method_number_t)0x003C006E) /**< basic.recover method id @internal \ - 60, 110; 3932270 */ -/** basic.recover method fields */ -typedef struct amqp_basic_recover_t_ { - amqp_boolean_t requeue; /**< requeue */ -} amqp_basic_recover_t; - -#define AMQP_BASIC_RECOVER_OK_METHOD \ - ((amqp_method_number_t)0x003C006F) /**< basic.recover-ok method id \ - @internal 60, 111; 3932271 */ -/** basic.recover-ok method fields */ -typedef struct amqp_basic_recover_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_basic_recover_ok_t; - -#define AMQP_BASIC_NACK_METHOD \ - ((amqp_method_number_t)0x003C0078) /**< basic.nack method id @internal 60, \ - 120; 3932280 */ -/** basic.nack method fields */ -typedef struct amqp_basic_nack_t_ { - uint64_t delivery_tag; /**< delivery-tag */ - amqp_boolean_t multiple; /**< multiple */ - amqp_boolean_t requeue; /**< requeue */ -} amqp_basic_nack_t; - -#define AMQP_TX_SELECT_METHOD \ - ((amqp_method_number_t)0x005A000A) /**< tx.select method id @internal 90, \ - 10; 5898250 */ -/** tx.select method fields */ -typedef struct amqp_tx_select_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_select_t; - -#define AMQP_TX_SELECT_OK_METHOD \ - ((amqp_method_number_t)0x005A000B) /**< tx.select-ok method id @internal \ - 90, 11; 5898251 */ -/** tx.select-ok method fields */ -typedef struct amqp_tx_select_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_select_ok_t; - -#define AMQP_TX_COMMIT_METHOD \ - ((amqp_method_number_t)0x005A0014) /**< tx.commit method id @internal 90, \ - 20; 5898260 */ -/** tx.commit method fields */ -typedef struct amqp_tx_commit_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_commit_t; - -#define AMQP_TX_COMMIT_OK_METHOD \ - ((amqp_method_number_t)0x005A0015) /**< tx.commit-ok method id @internal \ - 90, 21; 5898261 */ -/** tx.commit-ok method fields */ -typedef struct amqp_tx_commit_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_commit_ok_t; - -#define AMQP_TX_ROLLBACK_METHOD \ - ((amqp_method_number_t)0x005A001E) /**< tx.rollback method id @internal \ - 90, 30; 5898270 */ -/** tx.rollback method fields */ -typedef struct amqp_tx_rollback_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_rollback_t; - -#define AMQP_TX_ROLLBACK_OK_METHOD \ - ((amqp_method_number_t)0x005A001F) /**< tx.rollback-ok method id @internal \ - 90, 31; 5898271 */ -/** tx.rollback-ok method fields */ -typedef struct amqp_tx_rollback_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_rollback_ok_t; - -#define AMQP_CONFIRM_SELECT_METHOD \ - ((amqp_method_number_t)0x0055000A) /**< confirm.select method id @internal \ - 85, 10; 5570570 */ -/** confirm.select method fields */ -typedef struct amqp_confirm_select_t_ { - amqp_boolean_t nowait; /**< nowait */ -} amqp_confirm_select_t; - -#define AMQP_CONFIRM_SELECT_OK_METHOD \ - ((amqp_method_number_t)0x0055000B) /**< confirm.select-ok method id \ - @internal 85, 11; 5570571 */ -/** confirm.select-ok method fields */ -typedef struct amqp_confirm_select_ok_t_ { - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_confirm_select_ok_t; - -/* Class property records. */ -#define AMQP_CONNECTION_CLASS \ - (0x000A) /**< connection class id @internal 10 \ - */ -/** connection class properties */ -typedef struct amqp_connection_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_connection_properties_t; - -#define AMQP_CHANNEL_CLASS (0x0014) /**< channel class id @internal 20 */ -/** channel class properties */ -typedef struct amqp_channel_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_channel_properties_t; - -#define AMQP_ACCESS_CLASS (0x001E) /**< access class id @internal 30 */ -/** access class properties */ -typedef struct amqp_access_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_access_properties_t; - -#define AMQP_EXCHANGE_CLASS (0x0028) /**< exchange class id @internal 40 */ -/** exchange class properties */ -typedef struct amqp_exchange_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_exchange_properties_t; - -#define AMQP_QUEUE_CLASS (0x0032) /**< queue class id @internal 50 */ -/** queue class properties */ -typedef struct amqp_queue_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_queue_properties_t; - -#define AMQP_BASIC_CLASS (0x003C) /**< basic class id @internal 60 */ -#define AMQP_BASIC_CONTENT_TYPE_FLAG (1 << 15) -#define AMQP_BASIC_CONTENT_ENCODING_FLAG (1 << 14) -#define AMQP_BASIC_HEADERS_FLAG (1 << 13) -#define AMQP_BASIC_DELIVERY_MODE_FLAG (1 << 12) -#define AMQP_BASIC_PRIORITY_FLAG (1 << 11) -#define AMQP_BASIC_CORRELATION_ID_FLAG (1 << 10) -#define AMQP_BASIC_REPLY_TO_FLAG (1 << 9) -#define AMQP_BASIC_EXPIRATION_FLAG (1 << 8) -#define AMQP_BASIC_MESSAGE_ID_FLAG (1 << 7) -#define AMQP_BASIC_TIMESTAMP_FLAG (1 << 6) -#define AMQP_BASIC_TYPE_FLAG (1 << 5) -#define AMQP_BASIC_USER_ID_FLAG (1 << 4) -#define AMQP_BASIC_APP_ID_FLAG (1 << 3) -#define AMQP_BASIC_CLUSTER_ID_FLAG (1 << 2) -/** basic class properties */ -typedef struct amqp_basic_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - amqp_bytes_t content_type; /**< content-type */ - amqp_bytes_t content_encoding; /**< content-encoding */ - amqp_table_t headers; /**< headers */ - uint8_t delivery_mode; /**< delivery-mode */ - uint8_t priority; /**< priority */ - amqp_bytes_t correlation_id; /**< correlation-id */ - amqp_bytes_t reply_to; /**< reply-to */ - amqp_bytes_t expiration; /**< expiration */ - amqp_bytes_t message_id; /**< message-id */ - uint64_t timestamp; /**< timestamp */ - amqp_bytes_t type; /**< type */ - amqp_bytes_t user_id; /**< user-id */ - amqp_bytes_t app_id; /**< app-id */ - amqp_bytes_t cluster_id; /**< cluster-id */ -} amqp_basic_properties_t; - -#define AMQP_TX_CLASS (0x005A) /**< tx class id @internal 90 */ -/** tx class properties */ -typedef struct amqp_tx_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_tx_properties_t; - -#define AMQP_CONFIRM_CLASS (0x0055) /**< confirm class id @internal 85 */ -/** confirm class properties */ -typedef struct amqp_confirm_properties_t_ { - amqp_flags_t _flags; /**< bit-mask of set fields */ - char dummy; /**< Dummy field to avoid empty struct */ -} amqp_confirm_properties_t; - -/* API functions for methods */ - -/** - * amqp_channel_open - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @returns amqp_channel_open_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_channel_open_ok_t *AMQP_CALL - amqp_channel_open(amqp_connection_state_t state, amqp_channel_t channel); -/** - * amqp_channel_flow - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] active active - * @returns amqp_channel_flow_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_channel_flow_ok_t *AMQP_CALL - amqp_channel_flow(amqp_connection_state_t state, amqp_channel_t channel, - amqp_boolean_t active); -/** - * amqp_exchange_declare - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] exchange exchange - * @param [in] type type - * @param [in] passive passive - * @param [in] durable durable - * @param [in] auto_delete auto_delete - * @param [in] internal internal - * @param [in] arguments arguments - * @returns amqp_exchange_declare_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_exchange_declare_ok_t *AMQP_CALL amqp_exchange_declare( - amqp_connection_state_t state, amqp_channel_t channel, - amqp_bytes_t exchange, amqp_bytes_t type, amqp_boolean_t passive, - amqp_boolean_t durable, amqp_boolean_t auto_delete, amqp_boolean_t internal, - amqp_table_t arguments); -/** - * amqp_exchange_delete - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] exchange exchange - * @param [in] if_unused if_unused - * @returns amqp_exchange_delete_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_exchange_delete_ok_t *AMQP_CALL - amqp_exchange_delete(amqp_connection_state_t state, amqp_channel_t channel, - amqp_bytes_t exchange, amqp_boolean_t if_unused); -/** - * amqp_exchange_bind - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] destination destination - * @param [in] source source - * @param [in] routing_key routing_key - * @param [in] arguments arguments - * @returns amqp_exchange_bind_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_exchange_bind_ok_t *AMQP_CALL - amqp_exchange_bind(amqp_connection_state_t state, amqp_channel_t channel, - amqp_bytes_t destination, amqp_bytes_t source, - amqp_bytes_t routing_key, amqp_table_t arguments); -/** - * amqp_exchange_unbind - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] destination destination - * @param [in] source source - * @param [in] routing_key routing_key - * @param [in] arguments arguments - * @returns amqp_exchange_unbind_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_exchange_unbind_ok_t *AMQP_CALL - amqp_exchange_unbind(amqp_connection_state_t state, amqp_channel_t channel, - amqp_bytes_t destination, amqp_bytes_t source, - amqp_bytes_t routing_key, amqp_table_t arguments); -/** - * amqp_queue_declare - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] queue queue - * @param [in] passive passive - * @param [in] durable durable - * @param [in] exclusive exclusive - * @param [in] auto_delete auto_delete - * @param [in] arguments arguments - * @returns amqp_queue_declare_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_queue_declare_ok_t *AMQP_CALL amqp_queue_declare( - amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue, - amqp_boolean_t passive, amqp_boolean_t durable, amqp_boolean_t exclusive, - amqp_boolean_t auto_delete, amqp_table_t arguments); -/** - * amqp_queue_bind - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] queue queue - * @param [in] exchange exchange - * @param [in] routing_key routing_key - * @param [in] arguments arguments - * @returns amqp_queue_bind_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_queue_bind_ok_t *AMQP_CALL amqp_queue_bind( - amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue, - amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_table_t arguments); -/** - * amqp_queue_purge - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] queue queue - * @returns amqp_queue_purge_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_queue_purge_ok_t *AMQP_CALL amqp_queue_purge(amqp_connection_state_t state, - amqp_channel_t channel, - amqp_bytes_t queue); -/** - * amqp_queue_delete - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] queue queue - * @param [in] if_unused if_unused - * @param [in] if_empty if_empty - * @returns amqp_queue_delete_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_queue_delete_ok_t *AMQP_CALL amqp_queue_delete( - amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue, - amqp_boolean_t if_unused, amqp_boolean_t if_empty); -/** - * amqp_queue_unbind - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] queue queue - * @param [in] exchange exchange - * @param [in] routing_key routing_key - * @param [in] arguments arguments - * @returns amqp_queue_unbind_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_queue_unbind_ok_t *AMQP_CALL amqp_queue_unbind( - amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue, - amqp_bytes_t exchange, amqp_bytes_t routing_key, amqp_table_t arguments); -/** - * amqp_basic_qos - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] prefetch_size prefetch_size - * @param [in] prefetch_count prefetch_count - * @param [in] global global - * @returns amqp_basic_qos_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_basic_qos_ok_t *AMQP_CALL amqp_basic_qos(amqp_connection_state_t state, - amqp_channel_t channel, - uint32_t prefetch_size, - uint16_t prefetch_count, - amqp_boolean_t global); -/** - * amqp_basic_consume - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] queue queue - * @param [in] consumer_tag consumer_tag - * @param [in] no_local no_local - * @param [in] no_ack no_ack - * @param [in] exclusive exclusive - * @param [in] arguments arguments - * @returns amqp_basic_consume_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_basic_consume_ok_t *AMQP_CALL amqp_basic_consume( - amqp_connection_state_t state, amqp_channel_t channel, amqp_bytes_t queue, - amqp_bytes_t consumer_tag, amqp_boolean_t no_local, amqp_boolean_t no_ack, - amqp_boolean_t exclusive, amqp_table_t arguments); -/** - * amqp_basic_cancel - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] consumer_tag consumer_tag - * @returns amqp_basic_cancel_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_basic_cancel_ok_t *AMQP_CALL - amqp_basic_cancel(amqp_connection_state_t state, amqp_channel_t channel, - amqp_bytes_t consumer_tag); -/** - * amqp_basic_recover - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @param [in] requeue requeue - * @returns amqp_basic_recover_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_basic_recover_ok_t *AMQP_CALL - amqp_basic_recover(amqp_connection_state_t state, amqp_channel_t channel, - amqp_boolean_t requeue); -/** - * amqp_tx_select - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @returns amqp_tx_select_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_tx_select_ok_t *AMQP_CALL amqp_tx_select(amqp_connection_state_t state, - amqp_channel_t channel); -/** - * amqp_tx_commit - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @returns amqp_tx_commit_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_tx_commit_ok_t *AMQP_CALL amqp_tx_commit(amqp_connection_state_t state, - amqp_channel_t channel); -/** - * amqp_tx_rollback - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @returns amqp_tx_rollback_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_tx_rollback_ok_t *AMQP_CALL amqp_tx_rollback(amqp_connection_state_t state, - amqp_channel_t channel); -/** - * amqp_confirm_select - * - * @param [in] state connection state - * @param [in] channel the channel to do the RPC on - * @returns amqp_confirm_select_ok_t - */ -AMQP_PUBLIC_FUNCTION -amqp_confirm_select_ok_t *AMQP_CALL - amqp_confirm_select(amqp_connection_state_t state, amqp_channel_t channel); - -AMQP_END_DECLS - -#endif /* AMQP_FRAMING_H */ diff --git a/ext/librabbitmq/centos_x64/include/amqp_tcp_socket.h b/ext/librabbitmq/centos_x64/include/amqp_tcp_socket.h deleted file mode 100644 index 3e9d82f5..00000000 --- a/ext/librabbitmq/centos_x64/include/amqp_tcp_socket.h +++ /dev/null @@ -1,68 +0,0 @@ -/** \file */ -/* - * Portions created by Alan Antonuk are Copyright (c) 2013-2014 Alan Antonuk. - * All Rights Reserved. - * - * Portions created by Michael Steinert are Copyright (c) 2012-2013 Michael - * Steinert. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** - * A TCP socket connection. - */ - -#ifndef AMQP_TCP_SOCKET_H -#define AMQP_TCP_SOCKET_H - -#include - -AMQP_BEGIN_DECLS - -/** - * Create a new TCP socket. - * - * Call amqp_connection_close() to release socket resources. - * - * \return A new socket object or NULL if an error occurred. - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -amqp_socket_t *AMQP_CALL amqp_tcp_socket_new(amqp_connection_state_t state); - -/** - * Assign an open file descriptor to a socket object. - * - * This function must not be used in conjunction with amqp_socket_open(), i.e. - * the socket connection should already be open(2) when this function is - * called. - * - * \param [in,out] self A TCP socket object. - * \param [in] sockfd An open socket descriptor. - * - * \since v0.4.0 - */ -AMQP_PUBLIC_FUNCTION -void AMQP_CALL amqp_tcp_socket_set_sockfd(amqp_socket_t *self, int sockfd); - -AMQP_END_DECLS - -#endif /* AMQP_TCP_SOCKET_H */ diff --git a/ext/librabbitmq/centos_x64/lib/librabbitmq.a b/ext/librabbitmq/centos_x64/lib/librabbitmq.a deleted file mode 100644 index d5c3e8b4..00000000 Binary files a/ext/librabbitmq/centos_x64/lib/librabbitmq.a and /dev/null differ diff --git a/include/ZeroTierDebug.h b/include/ZeroTierDebug.h index 561b5a63..aa7ab4fe 100644 --- a/include/ZeroTierDebug.h +++ b/include/ZeroTierDebug.h @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ /** * @file @@ -80,7 +67,7 @@ #define ZT_THREAD_ID (long)0 // (long)gettid() #endif #ifdef _WIN32 - #define ZT_THREAD_ID (long)0 // + #define ZT_THREAD_ID (long)0 // #endif #if defined(__JNI_LIB__) #include diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 5355cd3e..e5667acc 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ /* * This defines the external C API for ZeroTier's core network virtualization @@ -679,7 +666,7 @@ typedef struct /** * Internal node statistics - * + * * This structure is subject to change between versions. */ typedef struct diff --git a/macui/ZeroTier One.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macui/ZeroTier One.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/macui/ZeroTier One.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/make-bsd.mk b/make-bsd.mk index 8c7a6ad2..62a6d73e 100644 --- a/make-bsd.mk +++ b/make-bsd.mk @@ -13,7 +13,7 @@ ifeq ($(ZT_SANITIZE),1) endif # "make debug" is a shortcut for this ifeq ($(ZT_DEBUG),1) - CFLAGS+=-Wall -Werror -g -pthread $(INCLUDES) $(DEFS) + CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) LDFLAGS+= STRIP=echo ZT_TRACE=1 diff --git a/make-linux.mk b/make-linux.mk index 53537de8..f17b380f 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -1,4 +1,4 @@ -# Automagically pick clang or gcc, with preference for clang +# Automagically pick CLANG or RH/CentOS newer GCC if present # This is only done if we have not overridden these with an environment or CLI variable ifeq ($(origin CC),default) CC:=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) @@ -18,9 +18,6 @@ include objects.mk ONE_OBJS+=osdep/LinuxEthernetTap.o ONE_OBJS+=osdep/LinuxNetLink.o -NLTEST_OBJS+=osdep/LinuxNetLink.o node/InetAddress.o node/Utils.o node/Salsa20.o -NLTEST_OBJS+=nltest.o - # for central controller builds TIMESTAMP=$(shell date +"%Y%m%d%H%M") @@ -88,6 +85,9 @@ endif ifeq ($(ZT_QNAP), 1) override DEFS+=-D__QNAP__ endif +ifeq ($(ZT_UBIQUITI), 1) + override DEFS+=-D__UBIQUITI__ +endif ifeq ($(ZT_SYNOLOGY), 1) override CFLAGS+=-fPIC @@ -260,15 +260,22 @@ ifeq ($(ZT_OFFICIAL),1) override LDFLAGS+=-Wl,--wrap=memcpy -static-libstdc++ endif +ifeq ($(ZT_CONTROLLER),1) + LDLIBS+=-L/usr/pgsql-10/lib/ -lpq + DEFS+=-DZT_CONTROLLER_USE_LIBPQ + INCLUDES+=-I/usr/pgsql-10/include -Iext/hiredis-vip-0.3.0 + ONE_OBJS+=ext/hiredis-vip-0.3.0/adlist.o ext/hiredis-vip-0.3.0/async.o ext/hiredis-vip-0.3.0/command.o ext/hiredis-vip-0.3.0/crc16.o ext/hiredis-vip-0.3.0/dict.o ext/hiredis-vip-0.3.0/hiarray.o ext/hiredis-vip-0.3.0/hircluster.o ext/hiredis-vip-0.3.0/hiredis.o ext/hiredis-vip-0.3.0/hiutil.o ext/hiredis-vip-0.3.0/net.o ext/hiredis-vip-0.3.0/read.o ext/hiredis-vip-0.3.0/sds.o +endif + # ARM32 hell -- use conservative CFLAGS ifeq ($(ZT_ARCHITECTURE),3) ifeq ($(shell if [ -e /usr/bin/dpkg ]; then dpkg --print-architecture; fi),armel) - override CFLAGS+=-march=armv5 -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm - override CXXFLAGS+=-march=armv5 -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm + override CFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm + override CXXFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm ZT_USE_ARM32_NEON_ASM_CRYPTO=0 else - override CFLAGS+=-march=armv5 -mno-unaligned-access -marm - override CXXFLAGS+=-march=armv5 -mno-unaligned-access -marm + override CFLAGS+=-march=armv5t -mno-unaligned-access -marm -fexceptions + override CXXFLAGS+=-march=armv5t -mno-unaligned-access -marm -fexceptions ZT_USE_ARM32_NEON_ASM_CRYPTO=0 endif endif @@ -322,7 +329,7 @@ manpages: FORCE doc: manpages clean: FORCE - rm -rf *.a *.so *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/miniupnpc/*.o ext/libnatpmp/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm .depend debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one doc/node_modules ext/misc/*.o debian/.debhelper debian/debhelper-build-stamp + rm -rf *.a *.so *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/miniupnpc/*.o ext/libnatpmp/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm .depend debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one doc/node_modules ext/misc/*.o debian/.debhelper debian/debhelper-build-stamp docker/zerotier-one distclean: clean @@ -331,19 +338,19 @@ realclean: distclean official: FORCE make -j4 ZT_OFFICIAL=1 all -central-controller: FORCE - make -j4 LDLIBS="-L/usr/pgsql-10/lib/ -lpq -Lext/librabbitmq/centos_x64/lib/ -lrabbitmq" CXXFLAGS="-I/usr/pgsql-10/include -I./ext/librabbitmq/centos_x64/include -fPIC" DEFS="-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER" ZT_OFFICIAL=1 ZT_USE_X64_ASM_ED25519=1 one +docker: FORCE + docker build --no-cache -f ext/installfiles/linux/zerotier-containerized/Dockerfile -t zerotier-containerized . -central-controller-docker: central-controller - docker build -t docker.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f docker/Dockerfile . +central-controller: FORCE + make -j4 ZT_CONTROLLER=1 ZT_OFFICIAL=1 ZT_USE_X64_ASM_ED25519=1 one + +central-controller-docker: FORCE + docker build --no-cache -t docker.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . debug: FORCE make ZT_DEBUG=1 one make ZT_DEBUG=1 selftest -nltest: $(NLTEST_OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o nltest $(NLTEST_OBJS) $(LDLIBS) - # Note: keep the symlinks in /var/lib/zerotier-one to the binaries since these # provide backward compatibility with old releases where the binaries actually # lived here. Folks got scripts. @@ -393,13 +400,13 @@ uninstall: FORCE # These are just for convenience for building Linux packages debian: FORCE - debuild -I -i -us -uc -nc -b + debuild --no-lintian -I -i -us -uc -nc -b debian-clean: FORCE rm -rf debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one debian/.debhelper debian/debhelper-build-stamp redhat: FORCE - rpmbuild -ba zerotier-one.spec + rpmbuild --target `rpm -q bash --qf "%{arch}"` -ba zerotier-one.spec # This installs the packages needed to build ZT locally on CentOS 7 and # is here largely for documentation purposes. diff --git a/make-mac.mk b/make-mac.mk index c71b3f77..d8b0c4c2 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -1,3 +1,4 @@ + CC=clang CXX=clang++ INCLUDES= @@ -8,6 +9,8 @@ CODESIGN=echo PRODUCTSIGN=echo CODESIGN_APP_CERT= CODESIGN_INSTALLER_CERT= +NOTARIZE=echo +NOTARIZE_USER_ID=null ZT_BUILD_PLATFORM=3 ZT_BUILD_ARCHITECTURE=2 @@ -16,14 +19,19 @@ ZT_VERSION_MINOR=$(shell cat version.h | grep -F VERSION_MINOR | cut -d ' ' -f 3 ZT_VERSION_REV=$(shell cat version.h | grep -F VERSION_REVISION | cut -d ' ' -f 3) ZT_VERSION_BUILD=$(shell cat version.h | grep -F VERSION_BUILD | cut -d ' ' -f 3) +# for central controller builds +TIMESTAMP=$(shell date +"%Y%m%d%H%M") + DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE) include objects.mk ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o ext/http-parser/http_parser.o ifeq ($(ZT_CONTROLLER),1) - LIBS+=-lpq -lrabbitmq + LIBS+=-L/usr/local/opt/libpq/lib -lpq DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER + INCLUDES+=-I/usr/local/opt/libpq/include -Iext/hiredis-vip-0.3.0 + ONE_OBJS+=ext/hiredis-vip-0.3.0/adlist.o ext/hiredis-vip-0.3.0/async.o ext/hiredis-vip-0.3.0/command.o ext/hiredis-vip-0.3.0/crc16.o ext/hiredis-vip-0.3.0/dict.o ext/hiredis-vip-0.3.0/hiarray.o ext/hiredis-vip-0.3.0/hircluster.o ext/hiredis-vip-0.3.0/hiredis.o ext/hiredis-vip-0.3.0/hiutil.o ext/hiredis-vip-0.3.0/net.o ext/hiredis-vip-0.3.0/read.o ext/hiredis-vip-0.3.0/sds.o endif # Official releases are signed with our Apple cert and apply software updates by default @@ -34,6 +42,8 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1) PRODUCTSIGN=productsign CODESIGN_APP_CERT="Developer ID Application: ZeroTier, Inc (8ZD9JUCZ4V)" CODESIGN_INSTALLER_CERT="Developer ID Installer: ZeroTier, Inc (8ZD9JUCZ4V)" + NOTARIZE=xcrun altool + NOTARIZE_USER_ID="adam.ierymenko@gmail.com" else DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"download\"" endif @@ -76,7 +86,7 @@ ifeq ($(ZT_VAULT_SUPPORT),1) LIBS+=-lcurl endif -CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ +CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ all: one macui @@ -131,6 +141,8 @@ mac-dist-pkg: FORCE if [ -f "ZeroTier One Signed.pkg" ]; then mv -f "ZeroTier One Signed.pkg" "ZeroTier One.pkg"; fi rm -f zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* cat ext/installfiles/mac-update/updater.tmpl.sh "ZeroTier One.pkg" >zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_$(ZT_VERSION_MAJOR).$(ZT_VERSION_MINOR).$(ZT_VERSION_REV)_$(ZT_VERSION_BUILD).exe + $(NOTARIZE) -t osx -f "ZeroTier One.pkg" --primary-bundle-id --output-format xml --notarize-app -u $(NOTARIZE_USER_ID) + echo '*** When Apple notifies that the app is notarized, run: xcrun stapler staple "ZeroTier One.pkg"' # For ZeroTier, Inc. to build official signed packages official: FORCE @@ -139,6 +151,10 @@ official: FORCE make ZT_OFFICIAL_RELEASE=1 macui make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg +central-controller-docker: FORCE + #docker build --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=$(shell git name-rev --name-only HEAD) . + docker build -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=$(shell git name-rev --name-only HEAD) . + clean: rm -rf MacEthernetTapAgent *.dSYM build-* *.a *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* diff --git a/node/Address.hpp b/node/Address.hpp index ae0566fe..0749adbf 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_ADDRESS_HPP #define ZT_ADDRESS_HPP diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index b18ba540..ea84259b 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_ATOMICCOUNTER_HPP #define ZT_ATOMICCOUNTER_HPP diff --git a/node/Buffer.hpp b/node/Buffer.hpp index fe63eb2e..d0e152b9 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_BUFFER_HPP #define ZT_BUFFER_HPP diff --git a/node/C25519.hpp b/node/C25519.hpp index 640aedf5..db34f621 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_C25519_HPP #define ZT_C25519_HPP diff --git a/node/Capability.cpp b/node/Capability.cpp index fdf98bae..ad1b0f45 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "Capability.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/Capability.hpp b/node/Capability.hpp index 0704c513..12730028 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CAPABILITY_HPP #define ZT_CAPABILITY_HPP diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 614c6887..20ae229e 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "CertificateOfMembership.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index b2c63f9d..5043f4e6 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP #define ZT_CERTIFICATEOFMEMBERSHIP_HPP diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index d7266cd2..d6cd7d71 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "CertificateOfOwnership.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index fdffec3b..17c843bb 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP #define ZT_CERTIFICATEOFOWNERSHIP_HPP diff --git a/node/Constants.hpp b/node/Constants.hpp index ee656aae..4b88798d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CONSTANTS_HPP #define ZT_CONSTANTS_HPP @@ -480,7 +467,7 @@ /** * Delay between full-fledge pings of directly connected peers. - * + * * With multipath bonding enabled ping peers more often to measure * packet loss and latency. This uses more bandwidth so is disabled * by default to avoid increasing idle bandwidth use for regular diff --git a/node/Credential.hpp b/node/Credential.hpp index e7962fbb..5b58da2b 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_CREDENTIAL_HPP #define ZT_CREDENTIAL_HPP diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 8eb10a0b..5374b9e6 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP @@ -387,7 +374,7 @@ public: return this->add(key,(value) ? "1" : "0",1); } - /** + /** * Add a 64-bit integer (unsigned) as a hex value */ inline bool add(const char *key,uint64_t value) @@ -396,7 +383,7 @@ public: return this->add(key,Utils::hex(value,tmp),-1); } - /** + /** * Add a 64-bit integer (unsigned) as a hex value */ inline bool add(const char *key,int64_t value) @@ -410,7 +397,7 @@ public: } } - /** + /** * Add a 64-bit integer (unsigned) as a hex value */ inline bool add(const char *key,const Address &a) diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 10aab736..9a0f3e20 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_HASHTABLE_HPP #define ZT_HASHTABLE_HPP diff --git a/node/Identity.cpp b/node/Identity.cpp index e914b270..4e92765f 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/node/Identity.hpp b/node/Identity.hpp index f559bcc5..28d1f004 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_IDENTITY_HPP #define ZT_IDENTITY_HPP diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index b774f1df..331446ce 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -126,6 +113,9 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); return false; } + } catch (int ztExcCode) { + RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); + return true; } catch ( ... ) { RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); return true; @@ -532,7 +522,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + if (((ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6) + (count * 5)) <= size()) + RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); } } break; diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 5c4f896b..cf9a6474 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_INCOMINGPACKET_HPP #define ZT_INCOMINGPACKET_HPP diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 15d2f878..3eee1d4b 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index ce65bcd0..e16ae43b 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_INETADDRESS_HPP #define ZT_INETADDRESS_HPP diff --git a/node/MAC.hpp b/node/MAC.hpp index e1e20e37..3f7b0060 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MAC_HPP #define ZT_MAC_HPP diff --git a/node/Membership.cpp b/node/Membership.cpp index 031eb0b7..100946b2 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include diff --git a/node/Membership.hpp b/node/Membership.hpp index 73e11c6c..caff957b 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MEMBERSHIP_HPP #define ZT_MEMBERSHIP_HPP @@ -194,8 +181,38 @@ private: inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; } inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const { - if ((ip.isV6())&&(nconf.ndpEmulation())&&((InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))||(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip)))) { - return true; + if ((ip.isV6())&&(nconf.ndpEmulation())) { + const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); + for(unsigned int i=0;isin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) { + prefixMatches = false; + break; + } + } + if (prefixMatches) + return true; + break; + } + } + + const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt())); + for(unsigned int i=0;isin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) { + prefixMatches = false; + break; + } + } + if (prefixMatches) + return true; + break; + } + } } return false; } diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index 184df1ce..a38b284d 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MULTICASTGROUP_HPP #define ZT_MULTICASTGROUP_HPP diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index a25b7f05..82babae0 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 971f84af..f4c80108 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MULTICASTER_HPP #define ZT_MULTICASTER_HPP diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 1c8fb81e..14b6c81f 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MUTEX_HPP #define ZT_MUTEX_HPP @@ -51,11 +38,11 @@ public: inline void lock() const { - const uint16_t myTicket = __sync_fetch_and_add(&(const_cast(this)->nextTicket),1); + const uint16_t myTicket = __sync_fetch_and_add(&(const_cast(this)->nextTicket),1); while (nowServing != myTicket) { __asm__ __volatile__("rep;nop"::); __asm__ __volatile__("":::"memory"); - } + } } inline void unlock() const diff --git a/node/Network.cpp b/node/Network.cpp index 4458c9b0..cfdbb376 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/node/Network.hpp b/node/Network.hpp index 5e573812..701a4611 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_NETWORK_HPP #define ZT_NETWORK_HPP @@ -370,7 +357,7 @@ public: /** * Push credentials if we haven't done so in a very long time - * + * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param to Destination peer address * @param now Current time diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 20ad2e25..e45a111d 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index ddad52a5..12bbf775 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_NETWORKCONFIG_HPP #define ZT_NETWORKCONFIG_HPP diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index 1cbbd3ff..b344787b 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_NETWORKCONFIGMASTER_HPP #define ZT_NETWORKCONFIGMASTER_HPP diff --git a/node/Node.cpp b/node/Node.cpp index 237da463..5330b74c 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -501,7 +488,7 @@ ZT_PeerList *Node::peers() const p->paths[p->pathCount].expired = 0; p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; p->paths[p->pathCount].latency = (float)(*path)->latency(); - p->paths[p->pathCount].packetDelayVariance = (*path)->packetDelayVariance(); + p->paths[p->pathCount].packetDelayVariance = (*path)->packetDelayVariance(); p->paths[p->pathCount].throughputDisturbCoeff = (*path)->throughputDisturbanceCoefficient(); p->paths[p->pathCount].packetErrorRatio = (*path)->packetErrorRatio(); p->paths[p->pathCount].packetLossRatio = (*path)->packetLossRatio(); diff --git a/node/Node.hpp b/node/Node.hpp index a6f92eb1..21d49f51 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_NODE_HPP #define ZT_NODE_HPP diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index a162c8a5..1f2090ec 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "Constants.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 42063995..a40dc80f 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_OUTBOUNDMULTICAST_HPP #define ZT_OUTBOUNDMULTICAST_HPP diff --git a/node/Packet.cpp b/node/Packet.cpp index 5d0885d3..25006416 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/node/Packet.hpp b/node/Packet.hpp index fcb81489..53a1883c 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_N_PACKET_HPP #define ZT_N_PACKET_HPP diff --git a/node/Path.cpp b/node/Path.cpp index 2adb351c..e209e9c0 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "Path.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/Path.hpp b/node/Path.hpp index bc28c734..fc5dbff1 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_PATH_HPP #define ZT_PATH_HPP diff --git a/node/Peer.cpp b/node/Peer.cpp index f9e452c1..3c45d53f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "../version.h" #include "Constants.hpp" diff --git a/node/Peer.hpp b/node/Peer.hpp index dddd8fc0..ef4645e9 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_PEER_HPP #define ZT_PEER_HPP diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 4614826e..936c7b4a 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_POLY1305_HPP #define ZT_POLY1305_HPP diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 04342569..6cc6c99d 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "Revocation.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 1d001a40..7fda5c66 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_REVOCATION_HPP #define ZT_REVOCATION_HPP diff --git a/node/RingBuffer.hpp b/node/RingBuffer.hpp index 0f29a89a..2d6cd194 100644 --- a/node/RingBuffer.hpp +++ b/node/RingBuffer.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_RINGBUFFER_H #define ZT_RINGBUFFER_H @@ -40,7 +27,7 @@ namespace ZeroTier { * A circular buffer * * For fast handling of continuously-evolving variables (such as path quality metrics). - * Using this, we can maintain longer sliding historical windows for important path + * Using this, we can maintain longer sliding historical windows for important path * metrics without the need for potentially expensive calls to memcpy/memmove. * * Some basic statistical functionality is implemented here in an attempt @@ -73,7 +60,7 @@ public: return buf + begin; } - /** + /** * Adjust buffer index pointer as if we copied data in * @param n Number of elements to copy in * @return Number of elements we copied in @@ -96,13 +83,13 @@ public: return n; } - /** - * Fast erase, O(1). + /** + * Fast erase, O(1). * Merely reset the buffer pointer, doesn't erase contents */ inline void reset() { consume(count()); } - /** + /** * adjust buffer index pointer as if we copied data out * @param n Number of elements we copied from the buffer * @return Number of elements actually available from the buffer diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index e8ee4c59..07ab4333 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_RUNTIMEENVIRONMENT_HPP #define ZT_RUNTIMEENVIRONMENT_HPP diff --git a/node/SHA512.hpp b/node/SHA512.hpp index cb7b40a8..676f35d5 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_SHA512_HPP #define ZT_SHA512_HPP diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 0fb9e4a4..f4684d82 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 7940f5ac..0b7774b6 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_SELFAWARENESS_HPP #define ZT_SELFAWARENESS_HPP diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index c7f9ea97..84b1d7b5 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_SHAREDPTR_HPP #define ZT_SHAREDPTR_HPP diff --git a/node/Switch.cpp b/node/Switch.cpp index 51f23f67..feb3d09a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -627,8 +614,9 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr &network, Packet & } // Don't apply QoS scheduling to ZT protocol traffic if (packet.verb() != Packet::VERB_FRAME && packet.verb() != Packet::VERB_EXT_FRAME) { + // just send packet normally, no QoS for ZT protocol traffic send(tPtr, packet, encrypt, flowId); - } + } _aqm_m.lock(); @@ -636,7 +624,6 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr &network, Packet & const Address dest(packet.destination()); TXQueueEntry *txEntry = new TXQueueEntry(dest,RR->node->now(),packet,encrypt,flowId); - ManagedQueue *selectedQueue = nullptr; for (size_t i=0; ioldQueues.size()) { // search old queues first (I think this is best since old would imply most recent usage of the queue) @@ -710,7 +697,7 @@ uint64_t Switch::control_law(uint64_t t, int count) return (uint64_t)(t + ZT_QOS_INTERVAL / sqrt(count)); } -Switch::dqr Switch::dodequeue(ManagedQueue *q, uint64_t now) +Switch::dqr Switch::dodequeue(ManagedQueue *q, uint64_t now) { dqr r; r.ok_to_drop = false; diff --git a/node/Switch.hpp b/node/Switch.hpp index 666ee053..f535cb8e 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_N_SWITCH_HPP #define ZT_N_SWITCH_HPP diff --git a/node/Tag.cpp b/node/Tag.cpp index 6c78f3e4..69a17a28 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "Tag.hpp" #include "RuntimeEnvironment.hpp" diff --git a/node/Tag.hpp b/node/Tag.hpp index 3f888ba9..ada31b8f 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_TAG_HPP #define ZT_TAG_HPP diff --git a/node/Topology.cpp b/node/Topology.cpp index 6d6beda3..01a81fcc 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "Constants.hpp" #include "Topology.hpp" @@ -35,33 +22,8 @@ namespace ZeroTier { -/* - * 2018-07-26 ZeroTier planet definition for the third planet of Sol: - * - * There are two roots, each of which is a cluster spread across multiple - * continents and providers. They are named Alice and Bob after the - * canonical example names used in cryptography. - * - * Alice: - * - * root-alice-ams-01: Amsterdam, Netherlands - * root-alice-joh-01: Johannesburg, South Africa - * root-alice-nyc-01: New York, New York, USA - * root-alice-arg-01: Buenos Aires, Argentina - * root-alice-sfo-01: San Francisco, California, USA - * root-alice-sgp-01: Singapore - * - * Bob: - * - * root-bob-dfw-01: Dallas, Texas, USA - * root-bob-fra-01: Frankfurt, Germany - * root-bob-par-01: Paris, France - * root-bob-syd-01: Sydney, Australia - * root-bob-tok-01: Tokyo, Japan - * root-bob-tor-01: Toronto, Canada - */ -#define ZT_DEFAULT_WORLD_LENGTH 634 -static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x64,0xd3,0x71,0xf0,0x58,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0xbf,0xfd,0xd5,0x32,0xf7,0x15,0x6e,0x02,0x6f,0xb9,0x01,0x0d,0xb5,0x7b,0x04,0xd8,0x3a,0xc5,0x17,0x39,0x04,0x36,0xfd,0x9d,0xc6,0x3d,0xa8,0xf3,0x8e,0x79,0xe7,0xc8,0x77,0x8d,0xcc,0x79,0xb8,0xab,0xc6,0x98,0x7c,0x9f,0x34,0x25,0x14,0xe1,0x2f,0xd7,0x97,0x11,0xec,0x34,0x4c,0x9f,0x0f,0xb4,0x85,0x0d,0x9b,0x11,0xd1,0xc2,0xce,0x00,0xc4,0x0a,0x13,0x4b,0xcb,0xc3,0xae,0x2e,0x16,0x00,0x4b,0xdc,0x90,0x5e,0x7e,0x9b,0x44,0x07,0x15,0x36,0x61,0x3c,0x64,0xaa,0xe9,0x46,0x78,0x3c,0xa7,0x18,0xc8,0xd8,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x7d,0x00,0x01,0x00,0x00,0x00,0x00,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x33,0xcc,0x08,0xf8,0xfa,0xcc,0x08,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x54,0x60,0x01,0x00,0xfc,0xcc,0x08,0x27,0x09,0x04,0x83,0xff,0x06,0x10,0x27,0x09,0x06,0x28,0x03,0xeb,0x80,0x00,0x00,0x00,0x0e,0x00,0x02,0x60,0x01,0x00,0xfc,0xcc,0x08,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x02,0x00,0xe0,0x01,0x08,0xfe,0xcc,0x08,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0xb7,0x40,0x01,0x08,0xfe,0xcc,0x08,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x6a,0x30,0x01,0x78,0x00,0xcd,0x08,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x64,0xcd,0x08,0x80,0x01,0xcd,0x08,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x26,0x70,0x01,0xfe,0x15,0xc4,0xf5,0x27,0x09}; +#define ZT_DEFAULT_WORLD_LENGTH 674 +static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x6c,0xf9,0x10,0xd4,0x79,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x3e,0x3a,0xe9,0xeb,0x4e,0x78,0x27,0xb8,0xeb,0x78,0xe7,0x0f,0x64,0xa0,0x14,0xce,0x3d,0x30,0x21,0x96,0x23,0x9d,0x07,0x85,0xa4,0x0b,0xc6,0xf3,0x03,0x48,0x12,0x66,0x09,0x2a,0x6f,0xa1,0x5b,0x55,0x71,0x43,0xe7,0x2d,0xb3,0xfc,0xfc,0x8e,0x6f,0xe5,0xbb,0x5d,0x80,0x76,0x28,0x8d,0x32,0x87,0x24,0x3e,0x59,0x32,0x3d,0x9f,0xd1,0x00,0x54,0xd4,0xa2,0x90,0x0d,0xfc,0x3a,0xc9,0x5e,0xd8,0x6b,0x11,0x24,0xf9,0x70,0x8b,0x6e,0xd9,0x09,0xec,0xce,0x59,0x06,0xa6,0x73,0xf4,0x46,0x34,0x45,0xcd,0x57,0x44,0x04,0x3a,0x46,0xf1,0xbf,0x30,0x00,0x76,0xe6,0x6f,0xab,0x33,0xe2,0x85,0x49,0xa6,0x2e,0xe2,0x06,0x4d,0x18,0x43,0x27,0x3c,0x2c,0x30,0x0b,0xa4,0x5c,0x3f,0x20,0xbe,0xf0,0x2d,0xba,0xd2,0x25,0x72,0x3b,0xb5,0x9a,0x9b,0xb4,0xb1,0x35,0x35,0x73,0x09,0x61,0xae,0xec,0xf5,0xa1,0x63,0xac,0xe4,0x77,0xcc,0xeb,0x07,0x27,0x02,0x5b,0x99,0xac,0x14,0xa5,0x16,0x6a,0x09,0xa3,0x00,0x04,0x04,0xb9,0xb4,0x0d,0x52,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xc8,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x09,0x04,0xb9,0xb4,0x0d,0x52,0x01,0xbb,0x06,0x2a,0x02,0x6e,0xa0,0xc8,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xbb,0xde,0x89,0x50,0xa8,0xb2,0x00,0x1b,0x3a,0xda,0x82,0x51,0xb9,0x1b,0x6b,0x6f,0xa6,0x53,0x5b,0x8c,0x7e,0x24,0x60,0x91,0x8f,0x4f,0x72,0x9a,0xbd,0xec,0x97,0xd3,0xc7,0xf3,0x79,0x68,0x68,0xfb,0x02,0xf0,0xde,0x0b,0x0e,0xe5,0x54,0xb2,0xd5,0x9f,0xc3,0x52,0x47,0x43,0xee,0xbf,0xcf,0x53,0x15,0xe7,0x90,0xed,0x6d,0x92,0xdb,0x5b,0xd1,0x0c,0x28,0xc0,0x9b,0x40,0xef,0x00,0x04,0x04,0xcf,0xf6,0x49,0xf5,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x90,0x02,0x05,0xcb,0x0e,0xc4,0x7a,0xff,0xfe,0x8f,0x69,0xd9,0x27,0x09,0x04,0xcf,0xf6,0x49,0xf5,0x01,0xbb,0x06,0x20,0x01,0x19,0xf0,0x90,0x02,0x05,0xcb,0x0e,0xc4,0x7a,0xff,0xfe,0x8f,0x69,0xd9,0x01,0xbb,0x34,0xe0,0xa5,0xe1,0x74,0x00,0x93,0xef,0xb5,0x09,0x34,0x78,0x8f,0x85,0x6d,0x5c,0xfb,0x9c,0xa5,0xbe,0x88,0xe8,0x5b,0x40,0x96,0x55,0x86,0xb7,0x5b,0xef,0xac,0x90,0x0d,0xf7,0x73,0x52,0xc1,0x45,0xa1,0xba,0x70,0x07,0x56,0x9d,0x37,0xc7,0x7b,0xfe,0x52,0xc0,0x99,0x9f,0x3b,0xdc,0x67,0xa4,0x7a,0x4a,0x60,0x00,0xb7,0x20,0xa8,0x83,0xce,0x47,0xaa,0x2f,0xb7,0xf8,0x00,0x04,0x04,0x93,0x4b,0x5c,0x02,0x27,0x09,0x06,0x26,0x04,0x13,0x80,0x30,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x27,0x09,0x04,0x93,0x4b,0x5c,0x02,0x01,0xbb,0x06,0x26,0x04,0x13,0x80,0x30,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0xbb,0x99,0x2f,0xcf,0x1d,0xb7,0x00,0x20,0x6e,0xd5,0x93,0x50,0xb3,0x19,0x16,0xf7,0x49,0xa1,0xf8,0x5d,0xff,0xb3,0xa8,0x78,0x7d,0xcb,0xf8,0x3b,0x8c,0x6e,0x94,0x48,0xd4,0xe3,0xea,0x0e,0x33,0x69,0x30,0x1b,0xe7,0x16,0xc3,0x60,0x93,0x44,0xa9,0xd1,0x53,0x38,0x50,0xfb,0x44,0x60,0xc5,0x0a,0xf4,0x33,0x22,0xbc,0xfc,0x8e,0x13,0xd3,0x30,0x1a,0x1f,0x10,0x03,0xce,0xb6,0x00,0x04,0x04,0xc3,0xb5,0xad,0x9f,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xc0,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x09,0x04,0xc3,0xb5,0xad,0x9f,0x01,0xbb,0x06,0x2a,0x02,0x6e,0xa0,0xc0,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xbb}; Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : RR(renv), diff --git a/node/Topology.hpp b/node/Topology.hpp index b6690f58..56d4591c 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_TOPOLOGY_HPP #define ZT_TOPOLOGY_HPP diff --git a/node/Trace.cpp b/node/Trace.cpp index e38aaa41..96abf5c7 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ //#define ZT_TRACE diff --git a/node/Trace.hpp b/node/Trace.hpp index 162df154..b2a77161 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_TRACE_HPP #define ZT_TRACE_HPP diff --git a/node/Utils.cpp b/node/Utils.cpp index 16d81f65..e714967a 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/node/Utils.hpp b/node/Utils.hpp index 86db8b02..5ba5b035 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_UTILS_HPP #define ZT_UTILS_HPP diff --git a/node/World.hpp b/node/World.hpp index 823d304d..3921f380 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_WORLD_HPP #define ZT_WORLD_HPP diff --git a/objects.mk b/objects.mk index 32f62588..efa2f3c0 100644 --- a/objects.mk +++ b/objects.mk @@ -33,7 +33,6 @@ ONE_OBJS=\ controller/FileDB.o \ controller/LFDB.o \ controller/PostgreSQL.o \ - controller/RabbitMQ.o \ osdep/EthernetTap.o \ osdep/ManagedRoute.o \ osdep/Http.o \ diff --git a/one.cpp b/one.cpp index 89acaace..99a3a575 100644 --- a/one.cpp +++ b/one.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -96,12 +83,8 @@ using namespace ZeroTier; static OneService *volatile zt1Service = (OneService *)0; #define PROGRAM_NAME "ZeroTier One" -#define COPYRIGHT_NOTICE "Copyright (c) 2011-2018 ZeroTier, Inc." -#define LICENSE_GRANT \ - "This is free software: you may copy, modify, and/or distribute this" ZT_EOL_S \ - "work under the terms of the GNU General Public License, version 3 or" ZT_EOL_S \ - "later as published by the Free Software Foundation." ZT_EOL_S \ - "No warranty expressed or implied." ZT_EOL_S +#define COPYRIGHT_NOTICE "Copyright (c) 2019 ZeroTier, Inc." +#define LICENSE_GRANT "Licensed under the ZeroTier BSL 1.1 (see LICENSE.txt)" /****************************************************************************/ /* zerotier-cli personality */ @@ -132,10 +115,10 @@ static void cliPrintHelp(const char *pn,FILE *out) fprintf(out," listpeers - List all peers" ZT_EOL_S); fprintf(out," peers - List all peers (prettier)" ZT_EOL_S); fprintf(out," listnetworks - List all networks" ZT_EOL_S); - fprintf(out," join - Join a network" ZT_EOL_S); - fprintf(out," leave - Leave a network" ZT_EOL_S); - fprintf(out," set - Set a network setting" ZT_EOL_S); - fprintf(out," get - Get a network setting" ZT_EOL_S); + fprintf(out," join - Join a network" ZT_EOL_S); + fprintf(out," leave - Leave a network" ZT_EOL_S); + fprintf(out," set - Set a network setting" ZT_EOL_S); + fprintf(out," get - Get a network setting" ZT_EOL_S); fprintf(out," listmoons - List moons (federated root sets)" ZT_EOL_S); fprintf(out," orbit - Join a moon via any member root" ZT_EOL_S); fprintf(out," deorbit - Leave a moon" ZT_EOL_S); @@ -143,7 +126,7 @@ static void cliPrintHelp(const char *pn,FILE *out) fprintf(out," Settings to use with [get/set] may include property names from " ZT_EOL_S); fprintf(out," the JSON output of \"zerotier-cli -j listnetworks\". Additionally, " ZT_EOL_S); fprintf(out," (ip, ip4, ip6, ip6plane, and ip6prefix can be used). For instance:" ZT_EOL_S); - fprintf(out," zerotier-cli get ip6plane will return the 6PLANE address" ZT_EOL_S); + fprintf(out," zerotier-cli get ip6plane will return the 6PLANE address" ZT_EOL_S); fprintf(out," assigned to this node." ZT_EOL_S); } diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index 86f047a8..43f7868d 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp index 1a21a207..93a8450b 100644 --- a/osdep/Arp.hpp +++ b/osdep/Arp.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_ARP_HPP #define ZT_ARP_HPP diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index a1e7a945..ae4f2165 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index 5b1fe2dc..d99cebef 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_BSDETHERNETTAP_HPP #define ZT_BSDETHERNETTAP_HPP diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index bf7aef28..660e6f0c 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_BINDER_HPP #define ZT_BINDER_HPP diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp index f8b79342..0a317288 100644 --- a/osdep/BlockingQueue.hpp +++ b/osdep/BlockingQueue.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_BLOCKINGQUEUE_HPP #define ZT_BLOCKINGQUEUE_HPP diff --git a/osdep/EthernetTap.cpp b/osdep/EthernetTap.cpp index 82290fc2..10fe6d89 100644 --- a/osdep/EthernetTap.cpp +++ b/osdep/EthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "EthernetTap.hpp" #include "OSUtils.hpp" @@ -132,4 +119,13 @@ std::shared_ptr EthernetTap::newInstance( EthernetTap::EthernetTap() {} EthernetTap::~EthernetTap() {} +bool EthernetTap::addIps(std::vector ips) +{ + for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { + if (!addIp(*i)) + return false; + } + return true; +} + } // namespace ZeroTier diff --git a/osdep/EthernetTap.hpp b/osdep/EthernetTap.hpp index fc8fc848..db52e6b4 100644 --- a/osdep/EthernetTap.hpp +++ b/osdep/EthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_ETHERNETTAP_HPP #define ZT_ETHERNETTAP_HPP @@ -58,6 +45,7 @@ public: virtual void setEnabled(bool en) = 0; virtual bool enabled() const = 0; virtual bool addIp(const InetAddress &ip) = 0; + virtual bool addIps(std::vector ips); // uses addIp() unless overridden virtual bool removeIp(const InetAddress &ip) = 0; virtual std::vector ips() const = 0; virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0; diff --git a/osdep/Http.cpp b/osdep/Http.cpp index 1ab58836..9ff1a068 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/osdep/Http.hpp b/osdep/Http.hpp index a277bc4e..d9cad4dc 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_HTTP_HPP #define ZT_HTTP_HPP diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index 5ed49eef..b340561e 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "../node/Constants.hpp" @@ -103,7 +90,7 @@ LinuxEthernetTap::LinuxEthernetTap( // ensure netlink connection is started (void)LinuxNetLink::getInstance(); - + OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid); Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally @@ -274,10 +261,9 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip) return true; } -#ifdef __SYNOLOGY__ -bool LinuxEthernetTap::addIpSyn(std::vector ips) +bool LinuxEthernetTap::addIps(std::vector ips) { - // Here we fill out interface config (ifcfg-dev) to prevent it from being killed +#ifdef __SYNOLOGY__ std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-"+_dev; std::string cfg_contents = "DEVICE="+_dev+"\nBOOTPROTO=static"; int ip4=0,ip6=0,ip4_tot=0,ip6_tot=0; @@ -305,13 +291,14 @@ bool LinuxEthernetTap::addIpSyn(std::vector ips) } } OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length()); - // Finaly, add IPs + // Finally, add IPs for(int i=0; i<(int)ips.size(); i++){ LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str()); } return true; -} #endif // __SYNOLOGY__ + return false; +} bool LinuxEthernetTap::addIp(const InetAddress &ip) { diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index 1acecb4b..7503c523 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_LINUXETHERNETTAP_HPP #define ZT_LINUXETHERNETTAP_HPP @@ -59,9 +46,7 @@ public: virtual void setEnabled(bool en); virtual bool enabled() const; virtual bool addIp(const InetAddress &ip); -#ifdef __SYNOLOGY__ - bool addIpSyn(std::vector ips); -#endif + virtual bool addIps(std::vector ips); virtual bool removeIp(const InetAddress &ip); virtual std::vector ips() const; virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); diff --git a/osdep/LinuxNetLink.cpp b/osdep/LinuxNetLink.cpp index 6a9ae8aa..8d4ce248 100644 --- a/osdep/LinuxNetLink.cpp +++ b/osdep/LinuxNetLink.cpp @@ -1,28 +1,19 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ + +#include "../node/Constants.hpp" + +#ifdef __LINUX__ #include "LinuxNetLink.hpp" @@ -68,7 +59,7 @@ LinuxNetLink::LinuxNetLink() setsockopt(_fd,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes)); _la.nl_family = AF_NETLINK; - _la.nl_pid = getpid()+1; + _la.nl_pid = 0; //getpid()+1; _la.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR|RTMGRP_IPV4_ROUTE|RTMGRP_IPV6_ROUTE|RTMGRP_NOTIFY; if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) { fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno)); @@ -90,7 +81,7 @@ LinuxNetLink::~LinuxNetLink() ::close(_fd); } -void LinuxNetLink::_setSocketTimeout(int fd, int seconds) +void LinuxNetLink::_setSocketTimeout(int fd, int seconds) { struct timeval tv; tv.tv_sec = seconds; @@ -163,7 +154,7 @@ int LinuxNetLink::_doRecv(int fd) nll = 0; break; } - + nll += rtn; _processMessage(nlp, nll); @@ -198,7 +189,7 @@ void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll) { for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll)) { - switch(nlp->nlmsg_type) + switch(nlp->nlmsg_type) { case RTM_NEWLINK: _linkAdded(nlp); @@ -234,7 +225,7 @@ void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp) char local[40] = {0}; char label[40] = {0}; char bcast[40] = {0}; - + for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) { switch(rtap->rta_type) { @@ -450,7 +441,7 @@ void LinuxNetLink::_requestIPv4Routes() struct sockaddr_nl la; la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); la.nl_groups = RTMGRP_IPV4_ROUTE; if(bind(fd, (struct sockaddr*)&la, sizeof(la))) { fprintf(stderr, "Error binding RTNETLINK (_requiestIPv4Routes #1): %s\n", strerror(errno)); @@ -505,7 +496,7 @@ void LinuxNetLink::_requestIPv6Routes() struct sockaddr_nl la; la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); la.nl_groups = RTMGRP_IPV6_ROUTE; if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno)); @@ -560,7 +551,7 @@ void LinuxNetLink::_requestInterfaceList() struct sockaddr_nl la; la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); la.nl_groups = RTMGRP_LINK; if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno)); @@ -616,7 +607,7 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c struct sockaddr_nl la; bzero(&la, sizeof(la)); la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno)); @@ -663,7 +654,7 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c if(src.isV4()) { rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); - + } else { rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); @@ -733,7 +724,7 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c struct sockaddr_nl la; la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno)); @@ -780,7 +771,7 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c if(src.isV4()) { rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); - + } else { rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); @@ -849,7 +840,7 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface) struct sockaddr_nl la; memset(&la,0,sizeof(la)); la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); if (addr.isV4()) { la.nl_groups = RTMGRP_IPV4_IFADDR; } else { @@ -878,7 +869,7 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface) close(fd); return; } - + int rtl = sizeof(struct ifaddrmsg); struct nl_adr_req req; bzero(&req, sizeof(struct nl_adr_req)); @@ -968,7 +959,7 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface) struct sockaddr_nl la; la.nl_family = AF_NETLINK; - la.nl_pid = getpid(); + la.nl_pid = 0; //getpid(); if (addr.isV4()) { la.nl_groups = RTMGRP_IPV4_IFADDR; } else { @@ -992,7 +983,7 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface) close(fd); return; } - + int rtl = sizeof(struct ifaddrmsg); struct nl_adr_req req; bzero(&req, sizeof(struct nl_adr_req)); @@ -1068,7 +1059,7 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface) close(fd); } -RouteList LinuxNetLink::getIPV4Routes() const +RouteList LinuxNetLink::getIPV4Routes() const { return _routes_ipv4; } @@ -1095,3 +1086,5 @@ int LinuxNetLink::_indexForInterface(const char *iface) } } // namespace ZeroTier + +#endif diff --git a/osdep/LinuxNetLink.hpp b/osdep/LinuxNetLink.hpp index b0bf24b3..01bde04b 100644 --- a/osdep/LinuxNetLink.hpp +++ b/osdep/LinuxNetLink.hpp @@ -1,32 +1,23 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_LINUX_NETLINK_HPP #define ZT_LINUX_NETLINK_HPP +#include "../node/Constants.hpp" + +#ifdef __LINUX__ + #include #include @@ -53,7 +44,7 @@ struct route_entry { typedef std::vector RouteList; /** - * Interface with Linux's RTNETLINK + * Interface with Linux's RTNETLINK */ class LinuxNetLink { @@ -122,8 +113,10 @@ private: // socket communication vars; int _fd; struct sockaddr_nl _la; -}; +}; } +#endif + #endif // ZT_LINUX_NETLINK_HPPS \ No newline at end of file diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index 237df470..028f8556 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "../node/Constants.hpp" diff --git a/osdep/MacEthernetTap.hpp b/osdep/MacEthernetTap.hpp index 2eef59be..6d5ce894 100644 --- a/osdep/MacEthernetTap.hpp +++ b/osdep/MacEthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_OSXETHERNETTAP_HPP #define ZT_OSXETHERNETTAP_HPP diff --git a/osdep/MacEthernetTapAgent.c b/osdep/MacEthernetTapAgent.c index b5ad1f62..a58a8d70 100644 --- a/osdep/MacEthernetTapAgent.c +++ b/osdep/MacEthernetTapAgent.c @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ /* * This creates a pair of feth devices with the lower numbered device @@ -30,10 +17,10 @@ * used to actually read and write packets. The latter gets no IP config * and is only used for I/O. The behavior of feth is similar to the * veth pairs that exist on Linux. - * + * * The feth device has only existed since MacOS Sierra, but that's fairly * long ago in Mac terms. - * + * * I/O with feth must be done using two different sockets. The BPF socket * is used to receive packets, while an AF_NDRV (low-level network driver * access) socket must be used to inject. AF_NDRV can't read IP frames @@ -41,20 +28,20 @@ * been handled, and while BPF can inject its MTU for injected packets * is limited to 2048. AF_NDRV packet injection is required to inject * ZeroTier's large MTU frames. - * + * * Benchmarks show that this performs similarly to the old tap.kext driver, * and a kext is no longer required. Splitting it off into an agent will * also make it easier to have zerotier-one itself drop permissions. - * + * * All this stuff is basically undocumented. A lot of tracing through * the Darwin/XNU kernel source was required to figure out how to make * this actually work. - * + * * See also: - * + * * https://apple.stackexchange.com/questions/337715/fake-ethernet-interfaces-feth-if-fake-anyone-ever-seen-this * https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/net/if_fake.c.auto.html - * + * */ #include diff --git a/osdep/MacEthernetTapAgent.h b/osdep/MacEthernetTapAgent.h index f6459523..2c891c36 100644 --- a/osdep/MacEthernetTapAgent.h +++ b/osdep/MacEthernetTapAgent.h @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MACETHERNETTAPAGENT_H #define ZT_MACETHERNETTAPAGENT_H diff --git a/osdep/MacKextEthernetTap.cpp b/osdep/MacKextEthernetTap.cpp index 4f0520a6..2325d594 100644 --- a/osdep/MacKextEthernetTap.cpp +++ b/osdep/MacKextEthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/osdep/MacKextEthernetTap.hpp b/osdep/MacKextEthernetTap.hpp index fbf2694b..f1a6f36f 100644 --- a/osdep/MacKextEthernetTap.hpp +++ b/osdep/MacKextEthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MacKextEthernetTap_HPP #define ZT_MacKextEthernetTap_HPP diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 56e7b094..a5dc5b3c 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "../node/Constants.hpp" diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index e1a43c26..d1f60d3f 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_MANAGEDROUTE_HPP #define ZT_MANAGEDROUTE_HPP diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp index 134bd246..21c02b48 100644 --- a/osdep/NeighborDiscovery.cpp +++ b/osdep/NeighborDiscovery.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include "NeighborDiscovery.hpp" #include "OSUtils.hpp" @@ -32,7 +19,7 @@ #include namespace ZeroTier { - + uint16_t calc_checksum (uint16_t *addr, int len) { int count = len; @@ -56,10 +43,10 @@ uint16_t calc_checksum (uint16_t *addr, int len) while (sum >> 16) { sum = (sum & 0xffff) + (sum >> 16); } - + // Checksum is one's compliment of sum. answer = ~sum; - + return (answer); } @@ -78,14 +65,14 @@ struct _option { { memset(mac, 0, sizeof(mac)); } - + uint8_t type; uint8_t length; uint8_t mac[6]; }; struct _neighbor_solicitation { - _neighbor_solicitation() + _neighbor_solicitation() : type(135) , code(0) , checksum(0) diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp index b660068a..5abf3129 100644 --- a/osdep/NeighborDiscovery.hpp +++ b/osdep/NeighborDiscovery.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_NEIGHBORDISCOVERY_HPP #define ZT_NEIGHBORDISCOVERY_HPP diff --git a/osdep/NetBSDEthernetTap.cpp b/osdep/NetBSDEthernetTap.cpp index 027f2ec3..1c0f017c 100644 --- a/osdep/NetBSDEthernetTap.cpp +++ b/osdep/NetBSDEthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/osdep/NetBSDEthernetTap.hpp b/osdep/NetBSDEthernetTap.hpp index a174816e..534712e4 100644 --- a/osdep/NetBSDEthernetTap.hpp +++ b/osdep/NetBSDEthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_NetBSDEthernetTap_HPP #define ZT_NetBSDEthernetTap_HPP diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 83c615de..3770f021 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -398,6 +385,10 @@ std::string OSUtils::platformDefaultHomePath() homeDir.erase(std::remove(homeDir.begin(), homeDir.end(), '\n'), homeDir.end()); return homeDir; #endif +#ifdef __UBIQUITI__ + // Only persistent location after firmware upgrades + return std::string("/config/zerotier-one"); +#endif // Check for user-defined environment variable before using defaults #ifdef __WINDOWS__ diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index afdb1bf1..172575a0 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_OSUTILS_HPP #define ZT_OSUTILS_HPP diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index 333e5c24..b65a520e 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_PHY_HPP #define ZT_PHY_HPP diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index 6b2409b6..caad3ed4 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifdef ZT_USE_MINIUPNPC diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp index a075b774..be2c6468 100644 --- a/osdep/PortMapper.hpp +++ b/osdep/PortMapper.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifdef ZT_USE_MINIUPNPC diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index 4d32ce86..4cd56994 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_THREAD_HPP #define ZT_THREAD_HPP diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 773c56c1..fb4b498d 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 7a863875..ea08b2fc 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_WINDOWSETHERNETTAP_HPP #define ZT_WINDOWSETHERNETTAP_HPP diff --git a/rule-compiler/rule-compiler.js b/rule-compiler/rule-compiler.js index 6e21c2dc..f9b3aafa 100644 --- a/rule-compiler/rule-compiler.js +++ b/rule-compiler/rule-compiler.js @@ -1,3 +1,16 @@ +/* + * Copyright (c)2019 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2023-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + 'use strict'; // Names for bits in characteristics -- 0==LSB, 63==MSB diff --git a/selftest.cpp b/selftest.cpp index 77c06cc0..115bc4cb 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/service/OneService.cpp b/service/OneService.cpp index 0d1dd337..22c4f82e 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include @@ -99,7 +86,6 @@ extern "C" { using json = nlohmann::json; #include "../controller/EmbeddedNetworkController.hpp" -#include "../controller/RabbitMQ.hpp" #include "../osdep/EthernetTap.hpp" #ifdef __WINDOWS__ #include "../osdep/WindowsEthernetTap.hpp" @@ -538,8 +524,6 @@ public: volatile bool _run; Mutex _run_m; - MQConfig *_mqc; - // end member variables ---------------------------------------------------- OneServiceImpl(const char *hp,unsigned int port) : @@ -575,7 +559,6 @@ public: ,_vaultPath("cubbyhole/zerotier") #endif ,_run(true) - ,_mqc(NULL) { _ports[0] = 0; _ports[1] = 0; @@ -600,7 +583,6 @@ public: delete _portMapper; #endif delete _controller; - delete _mqc; } virtual ReasonForTermination run() @@ -691,50 +673,56 @@ public: // than one device behind the same NAT tries to use the same internal // private address port number. Buggy NATs are a running theme. if (_allowSecondaryPort) { - _ports[1] = (_secondaryPort == 0) ? 20000 + ((unsigned int)_node->address() % 45500) : _secondaryPort; - for(int i=0;;++i) { - if (i > 1000) { - _ports[1] = 0; - break; - } else if (++_ports[1] >= 65536) { - _ports[1] = 20000; + if (_secondaryPort) { + _ports[1] = _secondaryPort; + } else { + _ports[1] = 20000 + ((unsigned int)_node->address() % 45500); + for(int i=0;;++i) { + if (i > 1000) { + _ports[1] = 0; + break; + } else if (++_ports[1] >= 65536) { + _ports[1] = 20000; + } + if (_trialBind(_ports[1])) + break; } - if (_trialBind(_ports[1])) - break; } } - #ifdef ZT_USE_MINIUPNPC if (_portMappingEnabled) { // If we're running uPnP/NAT-PMP, bind a *third* port for that. We can't // use the other two ports for that because some NATs do really funky // stuff with ports that are explicitly mapped that breaks things. if (_ports[1]) { - _ports[2] = (_tertiaryPort == 0) ? _ports[1] : _tertiaryPort; - for(int i=0;;++i) { - if (i > 1000) { - _ports[2] = 0; - break; - } else if (++_ports[2] >= 65536) { - _ports[2] = 20000; + if (_tertiaryPort) { + _ports[2] = _tertiaryPort; + } else { + _ports[2] = _ports[1]; + for(int i=0;;++i) { + if (i > 1000) { + _ports[2] = 0; + break; + } else if (++_ports[2] >= 65536) { + _ports[2] = 20000; + } + if (_trialBind(_ports[2])) + break; + } + if (_ports[2]) { + char uniqueName[64]; + OSUtils::ztsnprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.10llx@%u",_node->address(),_ports[2]); + _portMapper = new PortMapper(_ports[2],uniqueName); } - if (_trialBind(_ports[2])) - break; - } - if (_ports[2]) { - char uniqueName[64]; - OSUtils::ztsnprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.10llx@%u",_node->address(),_ports[2]); - _portMapper = new PortMapper(_ports[2],uniqueName); } } } #endif - // Delete legacy iddb.d if present (cleanup) OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str()); // Network controller is now enabled by default for desktop and server - _controller = new EmbeddedNetworkController(_node,_homePath.c_str(),_controllerDbPath.c_str(),_ports[0], _mqc); + _controller = new EmbeddedNetworkController(_node,_homePath.c_str(),_controllerDbPath.c_str(),_ports[0]); _node->setNetconfMaster((void *)_controller); // Join existing networks in networks.d @@ -925,7 +913,7 @@ public: } void readLocalSettings() - { + { // Read local configuration std::map ppc; @@ -998,15 +986,7 @@ public: if (cdbp.length() > 0) _controllerDbPath = cdbp; - json &rmq = settings["rabbitmq"]; - if (rmq.is_object() && _mqc == NULL) { - fprintf(stderr, "Reading RabbitMQ Config\n"); - _mqc = new MQConfig; - _mqc->port = rmq["port"]; - _mqc->host = OSUtils::jsonString(rmq["host"], "").c_str(); - _mqc->username = OSUtils::jsonString(rmq["username"], "").c_str(); - _mqc->password = OSUtils::jsonString(rmq["password"], "").c_str(); - } + // TODO: Redis config // Bind to wildcard instead of to specific interfaces (disables full tunnel capability) json &bind = settings["bind"]; @@ -1366,8 +1346,8 @@ public: if (j.is_object()) { seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str()); } + } catch (std::exception &exc) { } catch ( ... ) { - // discard invalid JSON } std::vector moons(_node->moons()); @@ -1416,8 +1396,8 @@ public: json &allowDefault = j["allowDefault"]; if (allowDefault.is_boolean()) localSettings.allowDefault = (bool)allowDefault; } + } catch (std::exception &exc) { } catch ( ... ) { - // discard invalid JSON } setNetworkSettings(nws->networks[i].nwid,localSettings); @@ -1725,8 +1705,9 @@ public: } } #ifdef __SYNOLOGY__ - if (!n.tap->addIpSyn(newManagedIps)) + if (!n.tap->addIps(newManagedIps)) { fprintf(stderr,"ERROR: unable to add ip addresses to ifcfg" ZT_EOL_S); + } #else for(std::vector::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) { if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) { @@ -2044,6 +2025,8 @@ public: return; } + } catch (std::exception &exc) { + _phy.close(sock); } catch ( ... ) { _phy.close(sock); } @@ -2152,6 +2135,8 @@ public: #endif _nets.erase(nwid); return -999; + } catch (int exc) { + return -999; } catch ( ... ) { return -999; // tap init failed } diff --git a/service/OneService.hpp b/service/OneService.hpp index e5125676..53bbe2b8 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_ONESERVICE_HPP #define ZT_ONESERVICE_HPP diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index df3d89c2..5800f860 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #include #include diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index 1fab7740..24a2bc72 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef ZT_SOFTWAREUPDATER_HPP #define ZT_SOFTWAREUPDATER_HPP diff --git a/version.h b/version.h index 10678793..2e427cc8 100644 --- a/version.h +++ b/version.h @@ -1,28 +1,15 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * You can be released from the requirements of the license by purchasing - * a commercial license. Buying such a license is mandatory as soon as you - * develop commercial closed-source software that incorporates or links - * directly against ZeroTier software without disclosing the source code - * of your own application. + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #ifndef _ZT_VERSION_H #define _ZT_VERSION_H @@ -40,7 +27,7 @@ /** * Revision */ -#define ZEROTIER_ONE_VERSION_REVISION 2 +#define ZEROTIER_ONE_VERSION_REVISION 6 /** * Build version diff --git a/windows/WinUI/AboutView.xaml b/windows/WinUI/AboutView.xaml index 43dca4c0..d07a8947 100644 --- a/windows/WinUI/AboutView.xaml +++ b/windows/WinUI/AboutView.xaml @@ -19,7 +19,7 @@ - + diff --git a/windows/WinUI/CentralAPI.cs b/windows/WinUI/CentralAPI.cs index b0b4a267..22bdc697 100644 --- a/windows/WinUI/CentralAPI.cs +++ b/windows/WinUI/CentralAPI.cs @@ -75,7 +75,15 @@ namespace WinUI { byte[] tmp = File.ReadAllBytes(centralConfigPath); string json = Encoding.UTF8.GetString(tmp).Trim(); - Central = JsonConvert.DeserializeObject(json); + CentralServer ctmp = JsonConvert.DeserializeObject(json); + if (ctmp != null) + { + Central = ctmp; + } + else + { + Central = new CentralServer(); + } } else { @@ -105,7 +113,10 @@ namespace WinUI { string json = JsonConvert.SerializeObject(Central); byte[] tmp = Encoding.UTF8.GetBytes(json); - File.WriteAllBytes(CentralConfigFile(), tmp); + if (tmp != null) + { + File.WriteAllBytes(CentralConfigFile(), tmp); + } } private void UpdateRequestHeaders() diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 2bcc8603..a91ed7d1 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -113,7 +113,20 @@ - + + false + false + false + true + StreamingSIMDExtensions2 + NoExtensions + false + false + false + false + StreamingSIMDExtensions2 + NoExtensions + @@ -207,37 +220,37 @@ {B00A4957-5977-4AC1-9EF4-571DC27EADA2} ZeroTierOne - 10.0.17134.0 + 10.0 Application true - v141 + v142 MultiByte Application true - v141 + v142 MultiByte Application true - v141 + v142 MultiByte Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte Static @@ -245,7 +258,7 @@ Application false - v141 + v142 true MultiByte Static diff --git a/windows/ZeroTierOne/ZeroTierOneService.cpp b/windows/ZeroTierOne/ZeroTierOneService.cpp index 8e0b9c34..7e4cbf02 100644 --- a/windows/ZeroTierOne/ZeroTierOneService.cpp +++ b/windows/ZeroTierOne/ZeroTierOneService.cpp @@ -1,23 +1,20 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #pragma region Includes +#if defined(_WIN32) || defined(_WIN64) + #include #include #include @@ -79,9 +76,7 @@ restart_node: ZeroTier::Mutex::Lock _l(_lock); delete _service; _service = (ZeroTier::OneService *)0; // in case newInstance() fails - _service = ZeroTier::OneService::newInstance( - ZeroTier::OneService::platformDefaultHomePath().c_str(), - ZT_DEFAULT_PORT); + _service = ZeroTier::OneService::newInstance(_path.c_str(), ZT_DEFAULT_PORT); } switch(_service->run()) { case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR: { @@ -123,10 +118,16 @@ restart_node: } } -void ZeroTierOneService::OnStart(DWORD dwArgc, LPSTR *lpszArgv) +void ZeroTierOneService::OnStart(DWORD dwArgc, PSTR *lpszArgv) { ZT_SVCDBG("ZeroTierOneService::OnStart()\r\n"); + if ((dwArgc > 1)&&(lpszArgv[1])&&(strlen(lpszArgv[1]) > 0)) { + this->_path = lpszArgv[1]; + } else { + this->_path = ZeroTier::OneService::platformDefaultHomePath(); + } + try { _thread = ZeroTier::Thread::start(this); } catch ( ... ) { @@ -155,3 +156,5 @@ void ZeroTierOneService::OnShutdown() // stop thread on system shutdown (if it hasn't happened already) OnStop(); } + +#endif diff --git a/windows/ZeroTierOne/ZeroTierOneService.h b/windows/ZeroTierOne/ZeroTierOneService.h index 9c23d0f5..c4edb820 100644 --- a/windows/ZeroTierOne/ZeroTierOneService.h +++ b/windows/ZeroTierOne/ZeroTierOneService.h @@ -1,23 +1,20 @@ /* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (c)2019 ZeroTier, Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Change Date: 2023-01-01 * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. */ +/****/ #pragma once +#if defined(_WIN32) || defined(_WIN64) + #include #include "ServiceBase.h" @@ -60,12 +57,15 @@ public: throw(); protected: - virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); - virtual void OnStop(); + virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); + virtual void OnStop(); virtual void OnShutdown(); private: + std::string _path; ZeroTier::OneService *volatile _service; ZeroTier::Mutex _lock; ZeroTier::Thread _thread; }; + +#endif diff --git a/zerotier-one.spec b/zerotier-one.spec index 6649e653..3767b540 100644 --- a/zerotier-one.spec +++ b/zerotier-one.spec @@ -1,9 +1,9 @@ Name: zerotier-one -Version: 1.4.2 -Release: 2%{?dist} +Version: 1.4.6 +Release: 1%{?dist} Summary: ZeroTier One network virtualization service -License: GPLv3 +License: ZeroTier BSL 1.1 URL: https://www.zerotier.com %if 0%{?rhel} >= 7 @@ -145,6 +145,9 @@ esac %endif %changelog +* Fri Aug 23 2019 Adam Ierymenko - 1.4.4-0.1 +- see https://github.com/zerotier/ZeroTierOne for release notes + * Mon Aug 04 2019 Adam Ierymenko - 1.4.2-0.1 - see https://github.com/zerotier/ZeroTierOne for release notes