diff --git a/.clang-format b/.clang-format index 400349f1..7411a0c6 100644 --- a/.clang-format +++ b/.clang-format @@ -57,7 +57,7 @@ SpacesInCStyleCastParentheses: 'false' SpacesInContainerLiterals: 'true' SpacesInParentheses: 'false' SpacesInSquareBrackets: 'false' -UseTab: 'Always' +UseTab: 'Never' --- Language: Cpp diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 4acef401..00000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -.git/ -workspace/ diff --git a/.drone.jsonnet b/.drone.jsonnet deleted file mode 100644 index 7daef37f..00000000 --- a/.drone.jsonnet +++ /dev/null @@ -1,256 +0,0 @@ -// -// tweakables -// - -local registry = "084037375216.dkr.ecr.us-east-2.amazonaws.com"; -local build_channel = "zerotier-builds"; -local release_channel = "zerotier-releases"; - -local targets = [ - { "os": "linux", distro: "redhat", "name": "el9", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el8", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "redhat", "name": "el7", "isas": [ "386", "amd64", "ppc64le"], "events": [ "tag" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2", "isas": [ "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2022", "isas": [ "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "fedora", "name": "fc38", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "fedora", "name": "fc37", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "fedora", "name": "fc36", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "jammy", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "focal", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "bionic", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "xenial", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "trusty", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "debian", "name": "bookworm", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "tag"] }, - { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "buster", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "debian", "name": "stretch", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "debian", "name": "jessie", "isas": [ "386", "armv7", "amd64" ], "events": [ "tag" ] }, - -// { "os": "windows", distro: "windows", "name": "windows", "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] }, -// { "os": "darwin", distro: "darwin", "name": "darwin", "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] }, - -]; - -local less_targets = [ - { "os": "linux", distro: "redhat", "name": "el9", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el8", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "jammy", "isas": [ "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "focal", "isas": [ "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, -]; - - -local native_targets = [ - { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, -]; - -local master_targets = [ - // - // copypasta from here - // - { "os": "linux", distro: "redhat", "name": "el9", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el8", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el7", "isas": [ "386", "amd64", "ppc64le"], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2022", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "fedora", "name": "fc38", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "fedora", "name": "fc37", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "fedora", "name": "fc36", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "jammy", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "focal", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "bionic", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "xenial", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "trusty", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "sid", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "bookworm", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "buster", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "stretch", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "jessie", "isas": [ "386", "armv7", "amd64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "windows", distro: "windows", "name": "win2k22", "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] } -]; - -// -// functions -// - -local pipeline_type(os) = if os == "darwin" then "exec" else "docker"; -local builder_image(os) = if os == "linux" then registry + "/honda-builder" else registry + "/windows-builder"; -local tester_image(os) = if os == "linux" then registry + "/honda-builder" else registry + "/windows-tester"; -local build_step_volumes(os) = if os == "linux" then [ { name: "zerotier-builds", path: "/zerotier-builds" } ] else []; -local release_step_volumes(os) = if os == "linux" then [ { name: "zerotier-releases", path: "/zerotier-releases" } ] else []; -local host_volumes(os) = if os == "linux" then [ - { name: "zerotier-builds", host: { path: "/zerotier-builds" } }, - { name: "zerotier-releases", host: { path: "/zerotier-releases" } }, -] else []; - -local index_image(distro) = - if distro == "debian" || distro == "ubuntu" then - registry + "/apt-builder" - else if distro == "redhat" || distro == "fedora" || distro == "amazon" then - registry + "/dnf-builder" - else if distro == "windows" then - registry + "/msi-builder" -; - -local copy_commands(os, distro, name, isa, version) = - if os == "linux" then [ - std.join(" ", [ "./ci/scripts/publish.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) - ] - else if os == "windows" then [ - "C:\\scripts\\fix-ec2-metadata.ps1", - "Get-ChildItem windows", - // "aws s3 cp windows\\bytey-SetupFiles\\bytey.msi s3://zerotier-builds/windows/" + version + "/bytey.msi", - ] else if os == "darwin" then [ - "echo hello" - ] -; - -local index_commands(os, channel, distro, name, isas) = - if os == "linux" then - [ "/usr/local/bin/index " + channel + " " + distro + " " + name + " " + std.join(" ", isas) ] - else if os == "windows" then - [ "Get-ChildItem -Recurse windows" ] -; - -local build_commands(os, distro, name, isa, version) = - if os == "linux" then - [ std.join(" ", [ "./ci/scripts/build.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) ] - else - if os == "windows" then - [ "windows/build.ps1", "windows/package.ps1" ] - else - if os == "darwin" then - [ "whoami" ] -; - -local test_commands(os, distro, name, isa, version) = - if os == "linux" then - [ std.join(" ", [ "./ci/scripts/test.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) ] - else - if os == "windows" then - [ "windows/testpackage.ps1 " + version ] -; - -// -// render -// - -local Build(os, distro, name, isa, events) = { - "kind": "pipeline", - "type": pipeline_type(os), - "name": std.join(" ", [ name, isa, "build" ]), - "pull": "always", - "clone": { "depth": 1, [ if os == "darwin" then "disable" ]: true }, - "steps": [ - { - "name": "build", - "image": builder_image(os), - "commands": build_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"), - "when": { "event": [ "push" ]}, - }, - { - "name": "release", - "image": builder_image(os), - "commands": build_commands(os, distro, name, isa, "${DRONE_TAG}"), - "when": { "event": [ "tag" ]}, - }, - { - "name": "copy build", - "image": builder_image(os), - "commands": copy_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"), - "volumes": build_step_volumes(os), - "when": { "event": [ "push" ]}, - }, - { - "name": "copy relase", - "image": builder_image(os), - "commands": copy_commands(os, distro, name, isa, "${DRONE_TAG}"), - "volumes": release_step_volumes(os), - "when": { "event": [ "tag" ]}, - }, - ], - "volumes": host_volumes(os), - "platform": { "os": os, [ if isa == "arm64" || isa == "armv7" then "arch" ]: "arm64" }, - "trigger": { "event": events } -}; - -local Test(os, distro, name, isa, events) = { - "kind": "pipeline", - "type": pipeline_type(os), - "name": std.join(" ", [ name, isa, "test"]), - "pull": "always", - "clone": { "depth": 1 }, - "steps": [ - { - "name": "test build", - "image": tester_image(os), - "volumes": build_step_volumes(os), - "commands": test_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"), - "when": { "event": [ "push" ]}, - }, - { - "name": "test release", - "image": tester_image(os), - "volumes": release_step_volumes(os), - "commands": test_commands(os, distro, name, isa, "${DRONE_TAG}"), - "when": { "event": [ "tag" ]}, - }, - ], - "volumes": host_volumes(os), - "platform": { "os": os, [ if isa == "arm64" || isa == "armv7" then "arch" ]: "arm64" }, - "depends_on": [ std.join(" ", [ name, "index" ]) ], - "trigger": { "event": events } -}; - -local Index(p) = { - "kind": "pipeline", - "type": pipeline_type(p.os), - "name": std.join(" ", [ p.name, "index" ]), - "pull": "always", - "clone": { "depth": 1 }, - "steps": [ - { - "name": "index build", - "image": index_image(p.distro), - "commands": index_commands(p.os, "zerotier-builds", p.distro, p.name, p.isas), - "volumes": build_step_volumes(p.os), - "environment":{ "GPG_PRIVATE_KEY": { from_secret: "gpg-private-key" }}, - "when": { "event": [ "push" ]}, - }, - { - "name": "index release", - "image": index_image(p.distro), - "commands": index_commands(p.os, "zerotier-releases", p.distro, p.name, p.isas), - "volumes": release_step_volumes(p.os), - "environment":{ "GPG_PRIVATE_KEY": { from_secret: "gpg-private-key" }}, - "when": { "event": [ "tag" ]}, - }, - ], - "volumes": host_volumes(p.os), - "platform": { "os": p.os }, - depends_on: std.flattenArrays([ [ std.join(" ", [ p.name, isa, "build" ]) ] for isa in p.isas ]), - "trigger": { "event": p.events } -}; - -// -// print -// - -std.flattenArrays([ - [ - Build(p.os, p.distro, p.name, isa, p.events) - for isa in p.isas - ] + - [ - Index(p) - ] - for p in native_targets - ]) + - std.flattenArrays([ - [ - Test(p.os, p.distro, p.name, isa, p.events) - for isa in p.isas - ] - for p in native_targets - ]) - \ No newline at end of file diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index b837b1b2..00000000 --- a/.drone.yml +++ /dev/null @@ -1,465 +0,0 @@ ---- -clone: - depth: 1 -kind: pipeline -name: bullseye 386 build -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -kind: pipeline -name: bullseye armv7 build -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} - ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -kind: pipeline -name: bullseye amd64 build -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} - ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -kind: pipeline -name: bullseye arm64 build -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} - ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye 386 build -- bullseye armv7 build -- bullseye amd64 build -- bullseye arm64 build -kind: pipeline -name: bullseye index -platform: - os: linux -pull: always -steps: -- commands: - - /usr/local/bin/index zerotier-builds debian bullseye 386 armv7 amd64 arm64 - environment: - GPG_PRIVATE_KEY: - from_secret: gpg-private-key - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/apt-builder - name: index build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - /usr/local/bin/index zerotier-releases debian bullseye 386 armv7 amd64 arm64 - environment: - GPG_PRIVATE_KEY: - from_secret: gpg-private-key - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/apt-builder - name: index release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye 386 test -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye armv7 test -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye amd64 test -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye arm64 test -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -kind: signature -hmac: 887a3ef78d3fe8f0149911e1e4876401dd7dd313b36eb893e791fa42f45d7768 - -... diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dbe5330b..00000000 --- a/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -ext/bin/tap-windows-ndis6/x64/zttap300.inf eol=crlf -ext/bin/tap-windows-ndis6/x64.old/zttap300.inf eol=crlf -ext/bin/tap-windows-ndis6/x86/zttap300.inf eol=crlf -windows/TapDriver6/zttap300.inf eol=crlf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..92a26742 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,46 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- +**Alternative, faster ways to get help** +If you have just started using ZeroTier, here are some places to get help: +- my.zerotier.com has a _Community_ tab. It's a live chat with other users and the developers. +- [ZeroTier Knowledge Base](https://zerotier.atlassian.net/wiki/spaces/SD/overview) +- www.zerotier.com has a Contact Us button +- email contact@zerotier.com + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Create a Network '...' +2. Install zerotier-one '....' +3. '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots or console output to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Mac, Linux, Windows, BSD] + - OS/Distribution Version + - ZeroTier Version [e.g. 1.2.4] + - Hardware [e.g. raspberry pi 3] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Version [e.g. 1.2.4] + +**Additional context** +Add any other context about the problem here. +- ZeroTier Network Configuration +- Router Config +- Firewall Config (try turning the firewall off) +- General Network Environment: [ e.g Home, University Campus, Corporate LAN ] + diff --git a/.github/ISSUE_TEMPLATE/bugs-and-issues.md b/.github/ISSUE_TEMPLATE/bugs-and-issues.md deleted file mode 100644 index 92e6978c..00000000 --- a/.github/ISSUE_TEMPLATE/bugs-and-issues.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: Bugs and Issues -about: Create a report to help us improve -title: '' -labels: NEEDS TRIAGE -assignees: '' - ---- - -# Before filing a Bug Report - -_Using these will ensure you get quicker support, and make this space available for code-related issues. Thank you!_ - -- [Docs Site](https://docs.zerotier.com/zerotier/troubleshooting) => Troubleshooting, quickstarts, and more advanced topics. -- [Discuss Forum](https://discuss.zerotier.com/) => Our discussion forum for users and support to mutually resolve issues & suggest ideas. -- [Reddit](https://www.reddit.com/r/zerotier/) => Our subreddit, which we monitor regularly and is fairly active. -- [Knowledge Base](https://zerotier.atlassian.net/wiki/spaces/SD/overview) => Older wiki. - -If you are having a connection issue, it's much easier to diagnose through the discussion forum or the ticket system. - - -# If you still want to file a Bug Report - -## Please let us know - -- What you expect to be happening. -- What is actually happening? -- Any steps to reproduce the error. -- Any relevant console output or screenshots. -- What operating system and ZeroTier version. Please try the latest ZeroTier release. - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 5a1e094c..066b2d92 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,13 +1,17 @@ --- name: Feature request about: Suggest an idea for this project -title: "[Feature Request] " -labels: suggestion -assignees: '' --- -If there is something you'd like to have added to ZeroTier, to go to https://discuss.zerotier.com/c/feature-requests/ instead. Issues there can be voted on and discussed in-depth. +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +**Describe the solution you'd like** +A clear and concise description of what you want to happen. -Thank you! +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/game-connection-issue.md b/.github/ISSUE_TEMPLATE/game-connection-issue.md deleted file mode 100644 index d7b3a9b2..00000000 --- a/.github/ISSUE_TEMPLATE/game-connection-issue.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: Game Connection Issue -about: Game issues are better served by forum posts -title: Please go to our Discuss or Reddit for game-related issues. Thanks! -labels: wontfix -assignees: '' - ---- - -Are you having trouble connecting to a game on your virtual network after installing ZeroTier? - -- [ ] Yes -- [ ] No - -If you answered yes, then it is very likely that your question would be better answered on our [Community Forums](https://discuss.zerotier.com) or [Reddit](https://www.reddit.com/r/zerotier/) community; we monitor both regularly. We also have extensive documentation on our [Knowledge Base](https://zerotier.atlassian.net/wiki/spaces/SD/overview). Thank you! diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index b9e1f490..00000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,123 +0,0 @@ -on: [ push ] - -jobs: - build_ubuntu: - runs-on: ubuntu-latest - steps: - - name: gitconfig - run: | - git config --global core.autocrlf input - # git config --global core.eol lf - - name: checkout - uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - targets: x86_64-unknown-linux-gnu - components: rustfmt, clippy - - - name: Set up cargo cache - uses: Swatinem/rust-cache@v2 - continue-on-error: false - with: - key: ${{ runner.os }}-cargo-${{ hashFiles('rustybits//Cargo.lock') }} - shared-key: ${{ runner.os }}-cargo- - workspaces: | - rustybits/ - - - name: make - run: make - - name: selftest - run: | - make selftest - ./zerotier-selftest - - name: 'Tar files' # keeps permissions (execute) - run: tar -cvf zerotier-one.tar zerotier-one - - name: Archive production artifacts - uses: actions/upload-artifact@v4 - with: - name: zerotier-one-ubuntu-x64 - path: zerotier-one.tar - retention-days: 7 - - build_macos: - runs-on: macos-latest - steps: - - name: gitconfig - run: | - git config --global core.autocrlf input - # git config --global core.eol lf - - name: checkout - uses: actions/checkout@v4 - - name: Install Rust aarch64 - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - target: aarch64-apple-darwin - components: rustfmt, clippy - - name: Install Rust x86_64 - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - target: x86_64-apple-darwin - components: rustfmt, clippy - - name: Set up cargo cache - uses: Swatinem/rust-cache@v2 - continue-on-error: false - with: - key: ${{ runner.os }}-cargo-${{ hashFiles('rustybits//Cargo.lock') }} - shared-key: ${{ runner.os }}-cargo- - workspaces: | - rustybits/ - - name: make - run: make - - name: selftest - run: | - make selftest - ./zerotier-selftest - - name: 'Tar files' # keeps permissions (execute) - run: tar -cvf zerotier-one.tar zerotier-one - - name: Archive production artifacts - uses: actions/upload-artifact@v4 - with: - name: zerotier-one-mac - path: zerotier-one.tar - retention-days: 7 - - - build_windows: - runs-on: windows-latest - steps: - - name: gitconfig - run: | - git config --global core.autocrlf true - # git config --global core.eol lf - - name: checkout - uses: actions/checkout@v4 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - target: aarch64-apple-darwin - components: rustfmt, clippy - - name: Set up cargo cache - uses: Swatinem/rust-cache@v2 - continue-on-error: false - with: - key: ${{ runner.os }}-cargo-${{ hashFiles('rustybits//Cargo.lock') }} - shared-key: ${{ runner.os }}-cargo- - workspaces: | - rustybits/ - - - name: setup msbuild - uses: microsoft/setup-msbuild@v2 - - name: msbuild - run: | - msbuild windows\ZeroTierOne.sln /m /p:Configuration=Release /property:Platform=x64 /t:ZeroTierOne - - name: Archive production artifacts - uses: actions/upload-artifact@v4 - with: - name: zerotier-one-windows - path: windows/Build - retention-days: 7 diff --git a/.github/workflows/validate-linux.sh b/.github/workflows/validate-linux.sh deleted file mode 100755 index a661f6f6..00000000 --- a/.github/workflows/validate-linux.sh +++ /dev/null @@ -1,497 +0,0 @@ -#!/bin/bash - -# This test script joins Earth and pokes some stuff - -TEST_NETWORK=8056c2e21c000001 -RUN_LENGTH=30 -TEST_FINISHED=false -ZTO_VER=$(git describe --tags $(git rev-list --tags --max-count=1)) -ZTO_COMMIT=$(git rev-parse HEAD) -ZTO_COMMIT_SHORT=$(git rev-parse --short HEAD) -TEST_DIR_PREFIX="$ZTO_VER-$ZTO_COMMIT_SHORT-test-results" - -TEST_OK=0 -TEST_FAIL=1 - -echo "Performing test on: $ZTO_VER-$ZTO_COMMIT_SHORT" -TEST_FILEPATH_PREFIX="$TEST_DIR_PREFIX/$ZTO_COMMIT_SHORT" -mkdir $TEST_DIR_PREFIX - -# How long we will wait for ZT to come online before considering it a failure -MAX_WAIT_SECS=30 - -ZT_PORT_NODE_1=9996 -ZT_PORT_NODE_2=9997 - -################################################################################ -# Multi-node connectivity and performance test # -################################################################################ - -test() { - - echo -e "\nPerforming pre-flight checks" - - check_exit_on_invalid_identity - - echo -e "\nRunning test for $RUN_LENGTH seconds" - - export NS1="ip netns exec ns1" - export NS2="ip netns exec ns2" - - export ZT1="$NS1 ./zerotier-cli -p9996 -D$(pwd)/node1" - # Specify custom port on one node to ensure that feature works - export ZT2="$NS2 ./zerotier-cli -p9997 -D$(pwd)/node2" - - echo -e "\nSetting up network namespaces..." - echo "Setting up ns1" - - ip netns add ns1 - $NS1 ip link set dev lo up - ip link add veth0 type veth peer name veth1 - ip link set veth1 netns ns1 - ip addr add 192.168.0.1/24 dev veth0 - ip link set dev veth0 up - - $NS1 ip addr add 192.168.0.2/24 dev veth1 - $NS1 ip link set dev veth1 up - - # Add default route - $NS1 ip route add default via 192.168.0.1 - - iptables -t nat -A POSTROUTING -s 192.168.0.0/255.255.255.0 \ - -o eth0 -j MASQUERADE - iptables -A FORWARD -i eth0 -o veth0 -j ACCEPT - iptables -A FORWARD -o eth0 -i veth0 -j ACCEPT - - echo "Setting up ns2" - ip netns add ns2 - $NS2 ip link set dev lo up - ip link add veth2 type veth peer name veth3 - ip link set veth3 netns ns2 - ip addr add 192.168.1.1/24 dev veth2 - ip link set dev veth2 up - - $NS2 ip addr add 192.168.1.2/24 dev veth3 - $NS2 ip link set dev veth3 up - $NS2 ip route add default via 192.168.1.1 - - iptables -t nat -A POSTROUTING -s 192.168.1.0/255.255.255.0 \ - -o eth0 -j MASQUERADE - iptables -A FORWARD -i eth0 -o veth2 -j ACCEPT - iptables -A FORWARD -o eth0 -i veth2 -j ACCEPT - - # Allow forwarding - sysctl -w net.ipv4.ip_forward=1 - - ################################################################################ - # Memory Leak Check # - ################################################################################ - - export FILENAME_MEMORY_LOG="$TEST_FILEPATH_PREFIX-memory.log" - - echo -e "\nStarting a ZeroTier instance in each namespace..." - - export time_test_start=$(date +%s) - - # Spam the CLI as ZeroTier is starting - spam_cli 100 - - echo "Starting memory leak check" - $NS1 sudo valgrind --demangle=yes --exit-on-first-error=yes \ - --error-exitcode=1 \ - --xml=yes \ - --xml-file=$FILENAME_MEMORY_LOG \ - --leak-check=full \ - ./zerotier-one node1 -p$ZT_PORT_NODE_1 -U >>node_1.log 2>&1 & - - # Second instance, not run in memory profiler - # Don't set up internet access until _after_ zerotier is running - # This has been a source of stuckness in the past. - $NS2 ip addr del 192.168.1.2/24 dev veth3 - $NS2 sudo ./zerotier-one node2 -U -p$ZT_PORT_NODE_2 >>node_2.log 2>&1 & - - sleep 10; # New HTTP control plane is a bit sluggish, so we delay here - - check_bind_to_correct_ports $ZT_PORT_NODE_1 - check_bind_to_correct_ports $ZT_PORT_NODE_2 - - $NS2 ip addr add 192.168.1.2/24 dev veth3 - $NS2 ip route add default via 192.168.1.1 - - echo -e "\nPing from host to namespaces" - - ping -c 3 192.168.0.1 - ping -c 3 192.168.1.1 - - echo -e "\nPing from namespace to host" - - $NS1 ping -c 3 192.168.0.1 - $NS1 ping -c 3 192.168.0.1 - $NS2 ping -c 3 192.168.0.2 - $NS2 ping -c 3 192.168.0.2 - - echo -e "\nPing from ns1 to ns2" - - $NS1 ping -c 3 192.168.0.1 - - echo -e "\nPing from ns2 to ns1" - - $NS2 ping -c 3 192.168.0.1 - - ################################################################################ - # Online Check # - ################################################################################ - - echo "Waiting for ZeroTier to come online before attempting test..." - node1_online=false - node2_online=false - both_instances_online=false - time_zt_node1_start=$(date +%s) - time_zt_node2_start=$(date +%s) - - for ((s = 0; s <= $MAX_WAIT_SECS; s++)); do - node1_online="$($ZT1 -j info | jq '.online' 2>/dev/null)" - node2_online="$($ZT2 -j info | jq '.online' 2>/dev/null)" - echo "Checking for online status: try #$s, node1:$node1_online, node2:$node2_online" - if [[ "$node2_online" == "true" && "$node1_online" == "true" ]]; then - export both_instances_online=true - export time_to_both_nodes_online=$(date +%s) - break - fi - sleep 1 - done - - echo -e "\n\nContents of ZeroTier home paths:" - - ls -lga node1 - tree node1 - ls -lga node2 - tree node2 - - echo -e "\n\nRunning ZeroTier processes:" - echo -e "\nNode 1:\n" - $NS1 ps aux | grep zerotier-one - echo -e "\nNode 2:\n" - $NS2 ps aux | grep zerotier-one - - echo -e "\n\nStatus of each instance:" - - echo -e "\n\nNode 1:\n" - $ZT1 status - echo -e "\n\nNode 2:\n" - $ZT2 status - - if [[ "$both_instances_online" != "true" ]]; then - exit_test_and_generate_report $TEST_FAIL "one or more nodes failed to come online" - fi - - echo -e "\nJoining networks" - - $ZT1 join $TEST_NETWORK - $ZT2 join $TEST_NETWORK - - sleep 10 - - node1_ip4=$($ZT1 get $TEST_NETWORK ip4) - node2_ip4=$($ZT2 get $TEST_NETWORK ip4) - - echo "node1_ip4=$node1_ip4" - echo "node2_ip4=$node2_ip4" - - echo -e "\nPinging each node" - - PING12_FILENAME="$TEST_FILEPATH_PREFIX-ping-1-to-2.txt" - PING21_FILENAME="$TEST_FILEPATH_PREFIX-ping-2-to-1.txt" - - $NS1 ping -c 16 $node2_ip4 >$PING12_FILENAME - $NS2 ping -c 16 $node1_ip4 >$PING21_FILENAME - - ping_loss_percent_1_to_2=$(cat $PING12_FILENAME | - grep "packet loss" | awk '{print $6}' | sed 's/%//') - ping_loss_percent_2_to_1=$(cat $PING21_FILENAME | - grep "packet loss" | awk '{print $6}' | sed 's/%//') - - # Normalize loss value - export ping_loss_percent_1_to_2=$(echo "scale=2; $ping_loss_percent_1_to_2/100.0" | bc) - export ping_loss_percent_2_to_1=$(echo "scale=2; $ping_loss_percent_2_to_1/100.0" | bc) - - ################################################################################ - # CLI Check # - ################################################################################ - - echo "Testing basic CLI functionality..." - - spam_cli 10 - - $ZT1 join $TEST_NETWORK - - $ZT1 -h - $ZT1 -v - $ZT1 status - $ZT1 info - $ZT1 listnetworks - $ZT1 peers - $ZT1 listpeers - - $ZT1 -j status - $ZT1 -j info - $ZT1 -j listnetworks - $ZT1 -j peers - $ZT1 -j listpeers - - $ZT1 dump - - $ZT1 get $TEST_NETWORK allowDNS - $ZT1 get $TEST_NETWORK allowDefault - $ZT1 get $TEST_NETWORK allowGlobal - $ZT1 get $TEST_NETWORK allowManaged - $ZT1 get $TEST_NETWORK bridge - $ZT1 get $TEST_NETWORK broadcastEnabled - $ZT1 get $TEST_NETWORK dhcp - $ZT1 get $TEST_NETWORK id - $ZT1 get $TEST_NETWORK mac - $ZT1 get $TEST_NETWORK mtu - $ZT1 get $TEST_NETWORK name - $ZT1 get $TEST_NETWORK netconfRevision - $ZT1 get $TEST_NETWORK nwid - $ZT1 get $TEST_NETWORK portDeviceName - $ZT1 get $TEST_NETWORK portError - $ZT1 get $TEST_NETWORK status - $ZT1 get $TEST_NETWORK type - - # Test an invalid command - $ZT1 get $TEST_NETWORK derpderp - - # TODO: Validate JSON - - # Performance Test - - export FILENAME_PERF_JSON="$TEST_FILEPATH_PREFIX-iperf.json" - - echo -e "\nBeginning performance test:" - - echo -e "\nStarting server:" - - echo "$NS1 iperf3 -s &" - sleep 1 - - echo -e "\nStarting client:" - sleep 1 - - echo "$NS2 iperf3 --json -c $node1_ip4 > $FILENAME_PERF_JSON" - - cat $FILENAME_PERF_JSON - - # Let ZeroTier idle long enough for various timers - - echo -e "\nIdling ZeroTier for $RUN_LENGTH seconds..." - sleep $RUN_LENGTH - - echo -e "\nLeaving networks" - - $ZT1 leave $TEST_NETWORK - $ZT2 leave $TEST_NETWORK - - sleep 5 - - exit_test_and_generate_report $TEST_OK "completed test" -} - -################################################################################ -# Generate report # -################################################################################ - -exit_test_and_generate_report() { - - echo -e "\nStopping memory check..." - sudo pkill -15 -f valgrind - sleep 10 - - time_test_end=$(date +%s) - - echo "Exiting test with reason: $2 ($1)" - - # Collect ZeroTier dump files - - echo -e "\nCollecting ZeroTier dump files" - - node1_id=$($ZT1 -j status | jq -r .address) - node2_id=$($ZT2 -j status | jq -r .address) - - $ZT1 dump - mv zerotier_dump.txt "$TEST_FILEPATH_PREFIX-node-dump-$node1_id.txt" - - $ZT2 dump - mv zerotier_dump.txt "$TEST_FILEPATH_PREFIX-node-dump-$node2_id.txt" - - # Copy ZeroTier stdout/stderr logs - - cp node_1.log "$TEST_FILEPATH_PREFIX-node-log-$node1_id.txt" - cp node_2.log "$TEST_FILEPATH_PREFIX-node-log-$node2_id.txt" - - # Generate report - - cat $FILENAME_MEMORY_LOG - - DEFINITELY_LOST=$(xmlstarlet sel -t -v '/valgrindoutput/error/xwhat' \ - $FILENAME_MEMORY_LOG | grep "definitely" | awk '{print $1;}') - POSSIBLY_LOST=$(xmlstarlet sel -t -v '/valgrindoutput/error/xwhat' \ - $FILENAME_MEMORY_LOG | grep "possibly" | awk '{print $1;}') - - # Generate coverage report artifact and summary - - FILENAME_COVERAGE_JSON="$TEST_FILEPATH_PREFIX-coverage.json" - FILENAME_COVERAGE_HTML="$TEST_FILEPATH_PREFIX-coverage.html" - - echo -e "\nGenerating coverage test report..." - - gcovr -r . --exclude ext --json-summary $FILENAME_COVERAGE_JSON \ - --html >$FILENAME_COVERAGE_HTML - - cat $FILENAME_COVERAGE_JSON - - COVERAGE_LINE_COVERED=$(cat $FILENAME_COVERAGE_JSON | jq .line_covered) - COVERAGE_LINE_TOTAL=$(cat $FILENAME_COVERAGE_JSON | jq .line_total) - COVERAGE_LINE_PERCENT=$(cat $FILENAME_COVERAGE_JSON | jq .line_percent) - - COVERAGE_LINE_COVERED="${COVERAGE_LINE_COVERED:-0}" - COVERAGE_LINE_TOTAL="${COVERAGE_LINE_TOTAL:-0}" - COVERAGE_LINE_PERCENT="${COVERAGE_LINE_PERCENT:-0}" - - # Default values - - DEFINITELY_LOST="${DEFINITELY_LOST:-0}" - POSSIBLY_LOST="${POSSIBLY_LOST:-0}" - ping_loss_percent_1_to_2="${ping_loss_percent_1_to_2:-100.0}" - ping_loss_percent_2_to_1="${ping_loss_percent_2_to_1:-100.0}" - time_to_both_nodes_online="${time_to_both_nodes_online:--1}" - - # Summarize and emit json for trend reporting - - FILENAME_SUMMARY="$TEST_FILEPATH_PREFIX-summary.json" - - time_length_test=$((time_test_end - time_test_start)) - if [[ $time_to_both_nodes_online != -1 ]]; - then - time_to_both_nodes_online=$((time_to_both_nodes_online - time_test_start)) - fi - #time_length_zt_join=$((time_zt_join_end-time_zt_join_start)) - #time_length_zt_leave=$((time_zt_leave_end-time_zt_leave_start)) - #time_length_zt_can_still_ping=$((time_zt_can_still_ping-time_zt_leave_start)) - - summary=$( - cat <$FILENAME_SUMMARY - cat $FILENAME_SUMMARY - - exit 0 -} - -################################################################################ -# CLI Check # -################################################################################ - -spam_cli() { - echo "Spamming CLI..." - # Rapidly spam the CLI with joins/leaves - - MAX_TRIES="${1:-10}" - - for ((s = 0; s <= MAX_TRIES; s++)); do - $ZT1 status - $ZT2 status - sleep 0.1 - done - - SPAM_TRIES=128 - - for ((s = 0; s <= SPAM_TRIES; s++)); do - $ZT1 join $TEST_NETWORK - done - - for ((s = 0; s <= SPAM_TRIES; s++)); do - $ZT1 leave $TEST_NETWORK - done - - for ((s = 0; s <= SPAM_TRIES; s++)); do - $ZT1 leave $TEST_NETWORK - $ZT1 join $TEST_NETWORK - done -} - -################################################################################ -# Check for proper exit on load of invalid identity # -################################################################################ - -check_exit_on_invalid_identity() { - echo "Checking ZeroTier exits on invalid identity..." - mkdir -p $(pwd)/exit_test - ZT1="sudo ./zerotier-one -p9999 $(pwd)/exit_test" - echo "asdfasdfasdfasdf" > $(pwd)/exit_test/identity.secret - echo "asdfasdfasdfasdf" > $(pwd)/exit_test/authtoken.secret - - echo "Launch ZeroTier with an invalid identity" - $ZT1 & - my_pid=$! - - echo "Waiting 5 seconds" - sleep 5 - - # check if process is running - kill -0 $my_pid - if [ $? -eq 0 ]; then - exit_test_and_generate_report $TEST_FAIL "Exit test FAILED: Process still running after being fed an invalid identity" - fi -} - -################################################################################ -# Check that we're binding to the primary port for TCP/TCP6/UDP # -################################################################################ - -check_bind_to_correct_ports() { - PORT_NUMBER=$1 - echo "Checking bound ports:" - sudo netstat -anp | grep "$PORT_NUMBER" | grep "zerotier" - if [[ $(sudo netstat -anp | grep "$PORT_NUMBER" | grep "zerotier" | grep "tcp") ]]; - then - : - else - exit_test_and_generate_report $TEST_FAIL "ZeroTier did not bind to tcp/$1" - fi - if [[ $(sudo netstat -anp | grep "$PORT_NUMBER" | grep "zerotier" | grep "tcp6") ]]; - then - : - else - exit_test_and_generate_report $TEST_FAIL "ZeroTier did not bind to tcp6/$1" - fi - if [[ $(sudo netstat -anp | grep "$PORT_NUMBER" | grep "zerotier" | grep "udp") ]]; - then - : - else - exit_test_and_generate_report $TEST_FAIL "ZeroTier did not bind to udp/$1" - fi -} - -test "$@" diff --git a/.github/workflows/validate-report.sh b/.github/workflows/validate-report.sh deleted file mode 100755 index 3ae4e1a1..00000000 --- a/.github/workflows/validate-report.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -################################################################################ -# Set exit code depending on tool reports # -################################################################################ - -DEFINITELY_LOST=$(cat *test-results/*summary.json | jq .num_definite_bytes_lost) -EXIT_CODE=$(cat *test-results/*summary.json | jq .exit_code) -EXIT_REASON=$(cat *test-results/*summary.json | jq .exit_reason) - -cat *test-results/*summary.json - -echo -e "\nBytes of memory definitely lost: $DEFINITELY_LOST" - -if [[ "$DEFINITELY_LOST" -gt 0 ]]; then - exit 1 -fi - -# Catch-all for other non-zero exit codes - -if [[ "$EXIT_CODE" -gt 0 ]]; then - echo "Test failed: $EXIT_REASON" - exit 1 -fi \ No newline at end of file diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml deleted file mode 100644 index bb362fb8..00000000 --- a/.github/workflows/validate.yml +++ /dev/null @@ -1,56 +0,0 @@ -on: - push: - workflow_dispatch: - -jobs: - build_ubuntu: - runs-on: ubuntu-latest - steps: - - name: gitconfig - run: | - git config --global core.autocrlf input - - - name: checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: x86_64-unknown-linux-gnu - override: true - components: rustfmt, clippy - - - name: Set up cargo cache - uses: Swatinem/rust-cache@v2 - continue-on-error: false - with: - key: ${{ runner.os }}-cargo-${{ hashFiles('zeroidc//Cargo.lock') }} - shared-key: ${{ runner.os }}-cargo- - workspaces: | - zeroidc/ - - - name: validate-1m-linux - env: - CC: 'gcc' - CXX: 'g++' - BRANCH: ${{ github.ref_name }} - run: | - sudo apt install -y valgrind xmlstarlet gcovr iperf3 tree - make one ZT_COVERAGE=1 ZT_TRACE=1 - sudo chmod +x ./.github/workflows/validate-linux.sh - sudo ./.github/workflows/validate-linux.sh - - - name: Archive test results - uses: actions/upload-artifact@v3 - with: - name: ${{github.sha}}-test-results - path: "*test-results*" - - - name: final-report - run: | - sudo chmod +x ./.github/workflows/validate-report.sh - sudo ./.github/workflows/validate-report.sh - diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index ba8b4afc..a1562793 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,56 @@ -# Main binaries created in *nix builds -/zerotier-one -/zerotier-idtool -/zerotier-cli -/zerotier-selftest -/zerotier -/nltest - -# IDE stuff -/.idea -/.nova -/compile_commands.json - -# OS-created garbage files from various platforms +build/ +/version.h .DS_Store +.Trashes +*.swp +._* +*~ +*~.nib .Apple* Thumbs.db @eaDir -._* +DerivedData/ +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 +*.xccheckout +xcuserdata/ +.vscode +__pycache__ +attic/world/*.c25519 +attic/world/mkworld +*.log +*.opensdf +*.user +*.cache +*.obj +*.tlog +*.pid +*.pkg +*.o +*.o-* +*.core +*.deb +*.rpm +*.autosave +*.tmp +.depend +node_modules +debian/files +debian/zerotier-one +debian/zerotier-one*.debhelper +debian/*.log +debian/zerotier-one.substvars +root/identity.* +root/config.* +/ext/installfiles/windows/chocolatey/zerotier-one/*.nupkg +/go/zerotier -# Windows build droppings /windows/ZeroTierOne.sdf /windows/ZeroTierOne.v11.suo /windows/x64 @@ -35,8 +67,10 @@ Thumbs.db /windows/WebUIWrapper/obj /windows/lib /ext/installfiles/windows/ZeroTier One-SetupFiles +/ext/installfiles/windows/Prerequisites /ext/installfiles/windows/*-cache -/ZeroTier One.msi +/*.msi +/windows/.vs *.vcxproj.backup /windows/TapDriver6/Win7Debug /windows/TapDriver6/win7Release @@ -45,48 +79,7 @@ Thumbs.db enc_temp_folder /windows/copyutil/bin /windows/copyutil/obj -.vs/ -# *nix/Mac build droppings -/build-* -/ZeroTierOneInstaller-* -/examples/docker/zerotier-one -/examples/docker/test-*.env -/world/mkworld -/world/*.c25519 -zt1-src.tar.gz -/MacEthernetTapAgent - -# Miscellaneous temporaries, build files, etc. -*.log -*.opensdf -*.user -*.cache -*.tlog -*.pid -*.pkg -*.o -/*.a -*.dylib -*.so -*.so.* -*.o-* -*.core -*.deb -*.rpm -*.autosave -*.tmp -.depend -node_modules -zt1_update_* -debian/files -debian/zerotier-one -debian/zerotier-one*.debhelper -debian/*.log -debian/zerotier-one.substvars -root-watcher/config.json - -# Java/Android/JNI build droppings java/obj/ java/libs/ java/bin/ @@ -98,45 +91,3 @@ java/build_win32/ windows/WinUI/obj/ windows/WinUI/bin/ windows/ZeroTierOne/Debug/ -/ext/installfiles/windows/chocolatey/zerotier-one/*.nupkg - -# Miscellaneous mac/Xcode droppings -.DS_Store -.Trashes -*.swp -*~.nib -DerivedData/ -*.pbxuser -*.mode1v3 -*.mode2v3 -*.perspectivev3 -!default.pbxuser -!default.mode1v3 -!default.mode2v3 -!default.perspectivev3 -*.xccheckout -xcuserdata/ -.vscode -__pycache__ -*~ -attic/world/*.c25519 -attic/world/mkworld -workspace/ -workspace2/ -zeroidc/target/ -tcp-proxy/target - -#snapcraft specifics -/parts/ -/stage/ -/prime/ - -*.snap - -.snapcraft -__pycache__ -*.pyc -*_source.tar.bz2 -snap/.snapcraft -tcp-proxy/tcp-proxy -rustybits/target diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..0e40fe8f --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ + +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/ZeroTierOne.iml b/.idea/ZeroTierOne.iml new file mode 100644 index 00000000..5e764c4f --- /dev/null +++ b/.idea/ZeroTierOne.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..a55e7a17 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dictionaries/api.xml b/.idea/dictionaries/api.xml new file mode 100644 index 00000000..53167764 --- /dev/null +++ b/.idea/dictionaries/api.xml @@ -0,0 +1,11 @@ + + + + apisocket + nwid + secrand + sockaddr + unmarshals + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..146ab09b --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..28a804d8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..6b5db685 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml new file mode 100644 index 00000000..97ad6d2d --- /dev/null +++ b/.idea/watcherTasks.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/.kick b/.kick deleted file mode 100644 index 28b8ee7f..00000000 --- a/.kick +++ /dev/null @@ -1,14 +0,0 @@ -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick diff --git a/AUTHORS.md b/AUTHORS.md index 84bb8631..2d765fb6 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -36,12 +36,6 @@ ZeroTier includes the following third party code, either in ext/ or incorporated * Home page: http://code.google.com/p/lz4/ * License grant: BSD 2-clause - * http-parser by Joyent, Inc. (many authors) - - * Files: ext/http-parser/* - * Home page: https://github.com/joyent/http-parser/ - * License grant: MIT/Expat - * C++11 json (nlohmann/json) by Niels Lohmann * Files: ext/json/* @@ -62,12 +56,6 @@ ZeroTier includes the following third party code, either in ext/ or incorporated * License grant: public domain * ZeroTier Modifications: slight cryptographically-irrelevant modifications for inclusion into ZeroTier core - * MiniUPNPC and libnatpmp by Thomas Bernard - - * Files: ext/libnatpmp/* ext/miniupnpc/* - * Home page: http://miniupnp.free.fr/ - * License grant: BSD attribution no-endorsement - * cpp-httplib by yhirose * Files: ext/cpp-httplib/* diff --git a/CMakeLists.txt b/CMakeLists.txt index fff7808e..e154a45c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,199 @@ -# CMake build script for libzerotiercore.a +cmake_minimum_required (VERSION 3.10) -cmake_minimum_required (VERSION 2.8) -project (zerotiercore) +if(${CMAKE_VERSION} VERSION_LESS 3.15) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() + cmake_policy(VERSION 3.15) +endif() -set (PROJ_DIR ${PROJECT_SOURCE_DIR}) -set (ZT_DEFS -std=c++11) +if(WIN32) + # If building on Windows, set minimum target to Windows 7 + set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE) +endif(WIN32) -file(GLOB core_src_glob ${PROJ_DIR}/node/*.cpp) -add_library(zerotiercore STATIC ${core_src_glob}) +set(ZEROTIER_ONE_VERSION_MAJOR 2 CACHE INTERNAL "") +set(ZEROTIER_ONE_VERSION_MINOR 0 CACHE INTERNAL "") +set(ZEROTIER_ONE_VERSION_REVISION 0 CACHE INTERNAL "") +set(ZEROTIER_ONE_VERSION_BUILD 0 CACHE INTERNAL "") -target_compile_options(zerotiercore PRIVATE ${ZT_DEFS}) +set(default_build_type "Release") +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + set(default_build_type "Debug") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +option(BUILD_CENTRAL_CONTROLLER "Build ZeroTier Central Controller" OFF) +option(ZT_TRACE "Trace Messages" OFF) +option(ZT_DEBUG_TRACE "Debug Trace Messages" OFF) + +if (BUILD_CENTRAL_CONTROLLER) + find_package(PostgreSQL REQUIRED) + set(ENABLE_SSL_SUPPORT OFF) + set(BUILD_SHARED_LIBS OFF) + set(BUILD_EXAMPLES OFF) + set(BUILD_TOOLS OFF) + set(BUILD_TESTS OFF) + set(BUILD_API_DOCS OFF) + add_subdirectory("ext/librabbitmq") +endif(BUILD_CENTRAL_CONTROLLER) + +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X Deployment Version") + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DZT_TRACE) +endif(CMAKE_BUILD_TYPE STREQUAL "Debug") + +project(zerotier + DESCRIPTION "ZeroTier Network Hypervisor" + LANGUAGES CXX C) + +if(WIN32) + add_definitions(-DNOMINMAX) +else(WIN32) + if(APPLE) + + message("Setting macOS Compiler Flags ${CMAKE_BUILD_TYPE}") + add_compile_options( + -Wall + -Wno-deprecated + -mmacosx-version-min=10.9 + $<$:-g> + $<$:-O0> + $<$:-Ofast> + $<$:-fPIE> + $<$:-flto> + $<$:-Ofast> + $<$:-fPIE> + $<$:-g> + ) + add_link_options( + -mmacosx-version-min=10.9 + $<$:-flto> + ) + + elseif ( + CMAKE_SYSTEM_NAME MATCHES "Linux" OR + CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR + CMAKE_SYSTEM_NAME MATCHES "OpenBSD" OR + CMAKE_SYSTEM_NAME MATCHES "NetBSD" + ) + + message("Setting Linux/BSD Compiler Flags (${CMAKE_BUILD_TYPE})") + add_compile_options( + -Wall + -Wno-deprecated + $<$:-g> + $<$:-O0> + $<$:-O3> + $<$:-fPIE> + $<$:-O3> + $<$:-fPIE> + $<$:-g> + ) + + endif(APPLE) +endif(WIN32) + +if ( + CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "i386" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "i486" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "i586" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "i686" +) + message("Adding SSE and AES-NI flags for processor ${CMAKE_SYSTEM_PROCESSOR}") + add_compile_options( + -maes + -mmmx + -mrdrnd + -mpclmul + -msse + -msse2 + -msse3 + -msse4.1 + ) +endif() + +if(ZT_TRACE) + add_definitions(-DZT_TRACE) +endif() +if(ZT_DEBUG_TRACE) + add_definitions(-DZT_DEBUG_TRACE) +endif() + +add_subdirectory(node) +add_subdirectory(controller) +add_subdirectory(osdep) +add_subdirectory(go/native) + +#if(WIN32) +# add_subdirectory("windows/WinUI") +# add_subdirectory("windows/copyutil") +# add_definitions(-DNOMINMAX) +#endif(WIN32) + +set( + zt_osdep + zt_core + zt_controller + zt_go_native +) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/version.h +) + +#set(src +# one.cpp +# "ext/http-parser/http_parser.c" +#) +#set(headers +# "ext/http-parser/http_parser.h" +#) + +if(WIN32) + set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi) +else(WIN32) + set(libs ${libs} pthread) +endif(WIN32) + +#if(WIN32) +# set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi) +# set(src +# ${src} +# "windows/ZeroTierOne/ServiceBase.cpp" +# "windows/ZeroTierOne/ServiceInstaller.cpp" +# "windows/ZeroTierOne/ZeroTierOneService.cpp" +# "windows/ZeroTierOne/ZeroTierOne.rc" +# ) +# set(headers +# ${headers} +# "windows/ZeroTierOne/ServiceBase.h" +# "windows/ZeroTierOne/ServiceInstaller.h" +# "windows/ZeroTierOne/ZeroTierOneService.h" +# ) +#else(WIN32) +# set(libs ${libs} pthread resolv) +#endif(WIN32) + +#if(BUILD_CENTRAL_CONTROLLER) +# set(libs ${libs} rabbitmq-static ${PostgreSQL_LIBRARIES}) +#endif(BUILD_CENTRAL_CONTROLLER) + +#add_executable(${PROJECT_NAME} ${src} ${headers}) +#target_link_libraries(${PROJECT_NAME} ${libs}) +#target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}) + +add_executable(zerotier-selftest selftest.cpp) +target_link_libraries(zerotier-selftest ${libs} zt_core zt_osdep) +target_compile_features(zerotier-selftest PUBLIC cxx_std_11) diff --git a/Dockerfile.ci b/Dockerfile.ci deleted file mode 100644 index 9ff3b011..00000000 --- a/Dockerfile.ci +++ /dev/null @@ -1,28 +0,0 @@ -# vim: ft=dockerfile - -FROM ubuntu:21.04 as stage - -RUN apt-get update -qq && apt-get -qq install make clang -COPY . . -RUN /usr/bin/make -RUN echo $PWD -RUN cp zerotier-one /usr/sbin - -FROM ubuntu:21.04 - -COPY --from=stage /zerotier-one /usr/sbin -RUN ln -sf /usr/sbin/zerotier-one /usr/sbin/zerotier-idtool -RUN ln -sf /usr/sbin/zerotier-one /usr/sbin/zerotier-cli - -RUN echo "${VERSION}" > /etc/zerotier-version -RUN rm -rf /var/lib/zerotier-one - - -RUN apt-get -qq update -RUN apt-get -qq install iproute2 net-tools fping 2ping iputils-ping iputils-arping - -COPY entrypoint.sh.release /entrypoint.sh -RUN chmod 755 /entrypoint.sh - -CMD [] -ENTRYPOINT ["/entrypoint.sh"] diff --git a/Dockerfile.release b/Dockerfile.release deleted file mode 100644 index 87ef6534..00000000 --- a/Dockerfile.release +++ /dev/null @@ -1,23 +0,0 @@ -# vim: ft=dockerfile - -FROM debian:bullseye - -ARG VERSION - -RUN apt-get update -qq && apt-get install curl gpg -y -RUN mkdir -p /usr/share/zerotier && \ - curl -o /usr/share/zerotier/tmp.asc "https://download.zerotier.com/contact%40zerotier.com.gpg" && \ - gpg --no-default-keyring --keyring /usr/share/zerotier/zerotier.gpg --import /usr/share/zerotier/tmp.asc && \ - rm -f /usr/share/zerotier/tmp.asc && \ - echo "deb [signed-by=/usr/share/zerotier/zerotier.gpg] http://download.zerotier.com/debian/bullseye bullseye main" > /etc/apt/sources.list.d/zerotier.list - -RUN apt-get update -qq && apt-get install zerotier-one=${VERSION} curl iproute2 net-tools iputils-ping openssl libssl1.1 -y -RUN rm -rf /var/lib/zerotier-one - -COPY entrypoint.sh.release /entrypoint.sh -RUN chmod 755 /entrypoint.sh - -HEALTHCHECK --interval=1s CMD bash /healthcheck.sh - -CMD [] -ENTRYPOINT ["/entrypoint.sh"] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..455115cb --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,90 @@ +#!/usr/bin/env groovy + +node('master') { + checkout scm + + 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 '''. /opt/rh/devtoolset-8/enable + rm -rf build/ + mkdir build && cd build + cmake .. + make -j4 + ./zerotier-selftest + ''' + } + } + catch (err) { + currentBuild.result = "FAILURE" + mattermostSend color: '#ff0000', message: "${env.JOB_NAME} broken on Centos 7 (<${env.BUILD_URL}|Open>)" + + throw err + } + } +// }, '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...>)" diff --git a/LICENSE.txt b/LICENSE.txt index 06a3fad6..78daf4c2 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -26,7 +26,7 @@ Additional Use Grant: You may make use of the Licensed Work, provided you ZeroTier behind the scenes to operate a service not related to ZeroTier network administration. - * Create Non-Open-Source Commercial Derivative Works + * Create Non-Open-Source Commercial Derviative Works (2) Link or directly include the Licensed Work in a commercial or for-profit application or other product @@ -47,7 +47,7 @@ Additional Use Grant: You may make use of the Licensed Work, provided you services, social welfare, senior care, child care, and the care of persons with disabilities. -Change Date: 2026-01-01 +Change Date: 2023-01-01 Change License: Apache License version 2.0 as published by the Apache Software Foundation diff --git a/Makefile b/Makefile index 1bedf304..9c82f78e 100644 --- a/Makefile +++ b/Makefile @@ -1,33 +1,20 @@ # Common makefile -- loads make rules for each platform -OSTYPE=$(shell uname -s) +BUILDDIR := build -ifeq ($(OSTYPE),Darwin) - include make-mac.mk -endif +.PHONY: all -ifeq ($(OSTYPE),Linux) - include make-linux.mk -endif +all: setup + cd ${BUILDDIR} && $(MAKE) -j$(shell getconf _NPROCESSORS_ONLN) -ifeq ($(OSTYPE),FreeBSD) - CC=clang - CXX=clang++ - ZT_BUILD_PLATFORM=7 - include make-bsd.mk -endif -ifeq ($(OSTYPE),OpenBSD) - CC=clang - CXX=clang++ - ZT_BUILD_PLATFORM=9 - include make-bsd.mk -endif +setup: + mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Release -ifeq ($(OSTYPE),NetBSD) - include make-netbsd.mk -endif +debug: + mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Debug && $(MAKE) -drone: - @echo "rendering .drone.yaml from .drone.jsonnet" - drone jsonnet --format --stream - drone sign zerotier/ZeroTierOne --save +clean: + rm -rf ${BUILDDIR} + +distclean: + rm -rf ${BUILDDIR} diff --git a/OFFICIAL-RELEASE-STEPS.md b/OFFICIAL-RELEASE-STEPS.md index f7842e9f..6de3526c 100644 --- a/OFFICIAL-RELEASE-STEPS.md +++ b/OFFICIAL-RELEASE-STEPS.md @@ -14,7 +14,7 @@ The version must be incremented in all of the following files: /debian/changelog /ext/installfiles/mac/ZeroTier One.pkgproj /ext/installfiles/windows/ZeroTier One.aip - ../DesktopUI/mac-app-template/ZeroTier.app/Contents/Info.plist + /windows/WinUI/AboutView.xaml The final .AIP file can only be edited on Windows with [Advanced Installer Enterprise](http://www.advancedinstaller.com/). In addition to incrementing the version be sure that a new product code is generated. (The "upgrade code" GUID on the other hand must never change.) diff --git a/README.docker.md b/README.docker.md deleted file mode 100644 index 0410f892..00000000 --- a/README.docker.md +++ /dev/null @@ -1,72 +0,0 @@ -# ZeroTier One in a container! - -**NOTE:** _Most of this information pertains to the docker image only. For more information about ZeroTier, check out the repository_: [here](https://github.com/zerotier/ZeroTierOne) or the [commercial website](https://www.zerotier.com). - -[ZeroTier](https://www.zerotier.com) 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. - -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 connections. - -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](https://github.com/zerotier/ZeroTierOne/blob/master/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](https://github.com/zerotier/ZeroTierOne/blob/master/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.). - -## Building the docker image - -Due to the network being a substrate for most applications and not an application unto itself, it makes sense that many people would want to build their own image based on our formula. - -The image is based on `debian:buster`. - -The `Dockerfile.release` file contains build instructions for building the described image in the rest of the README. The build is multi-arch and multi-release capable. - -These build arguments power the build: - -- `PACKAGE_BASEURL`: The base URL of the package repository to fetch from. (default: `https://download.zerotier.com/debian/buster/pool/main/z/zerotier-one/`) -- `ARCH`: The architecture of the package, in debian format. Must match your image arch. (default: `amd64`) -- `VERSION`: **REQUIRED** the version of ZeroTier to fetch. - -You can build this image like so: - -``` -docker build -f Dockerfile.release -t mybuild --build-arg VERSION=1.6.5 . -``` - -## Using the docker image - -The `entrypoint.sh` in the docker image is a little different; zerotier will be spawned in the background and the "main process" is actually just a sleeping shell script. This allows `zerotier-one` to gracefully terminate in some situations largely unique to docker. - -The `zerotier/zerotier` image requires the `CAP_NET_ADMIN` capability and the `/dev/net/tun` device must be forwarded to it. - -To join a network, simply supply it on the command-line; you can supply multiple networks. - -``` -docker run --name myzerotier --rm --cap-add NET_ADMIN --device /dev/net/tun zerotier/zerotier:latest abcdefdeadbeef00 -``` - -Once joining all the networks you have provided, it will sleep until terminated. Note that in ZeroTier, joining a network does not necessarily mean you have an IP or can do anything, really. You will want to probe the control socket: - -``` -docker exec myzerotier zerotier-cli listnetworks -``` - -To ensure you have a network available before trying to listen on it. Without pre-configuring the identity, this usually means going to the central admin panel and clicking the checkmark against your zerotier identity. - -### Environment Variables - -You can control a few settings including the identity used and the authtoken used to interact with the control socket (which you can forward and access through `localhost:9993`). - -- `ZEROTIER_JOIN_NETWORKS`: additional way to set networks to join. -- `ZEROTIER_API_SECRET`: replaces the `authtoken.secret` before booting and allows you to manage the control socket's authentication key. -- `ZEROTIER_IDENTITY_PUBLIC`: the `identity.public` file for zerotier-one. Use `zerotier-idtool` to generate one of these for you. -- `ZEROTIER_IDENTITY_SECRET`: the `identity.secret` file for zerotier-one. Use `zerotier-idtool` to generate one of these for you. - -### Tips - -- Forwarding port `:9993` to somewhere outside is probably a good idea for highly trafficked services. -- Forwarding `localhost:9993` to a control network where you can drive it remotely might be a good idea, just be sure to set your authtoken properly through environment variables. -- Pre-generating your identities could be much simpler to do via our [terraform plugin](https://github.com/zerotier/terraform-provider-zerotier) diff --git a/README.md b/README.md index e881ce81..b571459d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ ZeroTier - Global Area Networking ====== -*This document is written for a software developer audience. For information on using ZeroTier, see the: [Website](https://www.zerotier.com), [Documentation Site](https://docs.zerotier.com), and [Discussion Forum](https://discuss.zerotier.com).* - 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. 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 connections. +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." @@ -15,7 +13,7 @@ Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre 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](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.). +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 @@ -37,161 +35,74 @@ The base path contains the ZeroTier One service main entry point (`one.cpp`), se - `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.) + - `macui/`: a Macintosh menu-bar app for controlling ZeroTier One, written in Objective C. - `node/`: the ZeroTier virtual Ethernet switch core, which is designed to be entirely separate from the rest of the code and able to be built as a stand-alone OS-independent library. Note to developers: do not use C++11 features in here, since we want this to build on old embedded platforms that lack C++11 support. C++11 can be used elsewhere. - `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, and the Windows task bar app UI. - - `zeroidc/`: OIDC implementation used by ZeroTier service to log into SSO-enabled networks. (This part is written in Rust, and more Rust will be appearing in this repository in the future.) - -### Contributing - -Please do pull requests off of the `dev` branch. - -Releases are done by merging `dev` into `main` and then tagging and doing builds. ### Build and Platform Notes -To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/`. +To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/'. - **Mac** - - Xcode command line tools for macOS 10.13 or newer are required. - - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*. + - Xcode command line tools for OSX 10.8 or newer are required. - **Linux** - - The minimum compiler versions required are GCC/G++ 8.x or CLANG/CLANG++ 5.x. + - The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2. (Install `clang` on CentOS 7 as G++ is too old.) - Linux makefiles automatically detect and prefer clang/clang++ if present as it produces smaller and slightly faster binaries in most cases. You can override by supplying CC and CXX variables on the make command line. - - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*. - **Windows** - - Visual Studio 2022 on Windows 10 or newer. - - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*. + - Windows 7 or newer is supported. This *may* work on Vista but isn't officially supported there. It will not work on Windows XP. + - We build with Visual Studio 2017. Older versions may not work. Clang or MinGW will also probably work but may require some makefile hacking. - **FreeBSD** - GNU make is required. Type `gmake` to build. - - `binutils` is required. Type `pkg install binutils` to install. - - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*. - **OpenBSD** - There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`). - GNU make is required. Type `gmake` to build. - - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*. Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures. ### Running -Running *zerotier-one* with `-h` option will show help. +Running *zerotier-one* with -h will show help. -On Linux and BSD, if you built from source, you can start the service with: +On Linux and BSD you can start the service with: sudo ./zerotier-one -d -On most distributions, macOS, and Windows, the installer will start the service and set it up to start on boot. - A home folder for your system will automatically be created. -The service is controlled via the JSON API, which by default is available at `127.0.0.1:9993`. It also listens on `0.0.0.0:9993` which is only usable if `allowManagementFrom` is properly configured in `local.conf`. We include a *zerotier-cli* command line utility to make API calls for standard things like joining and leaving networks. The *authtoken.secret* file in the home folder contains the secret token for accessing this API. See [service/README.md](service/README.md) for API documentation. +The service is controlled via the JSON API, which by default is available at 127.0.0.1 port 9993. We include a *zerotier-cli* command line utility to make API calls for standard things like joining and leaving networks. The *authtoken.secret* file in the home folder contains the secret token for accessing this API. See README.md in [service/](service/) for API documentation. Here's where home folders live (by default) on each OS: * **Linux**: `/var/lib/zerotier-one` * **FreeBSD** / **OpenBSD**: `/var/db/zerotier-one` * **Mac**: `/Library/Application Support/ZeroTier/One` - * **Windows**: `\ProgramData\ZeroTier\One` (That's the default. The base 'shared app data' folder might be different if Windows is installed with a non-standard drive letter assignment or layout.) + * **Windows**: `\ProgramData\ZeroTier\One` (That's for Windows 7. The base 'shared app data' folder might be different on different Windows versions.) + +Running ZeroTier One on a Mac is the same, but OSX requires a kernel extension. We ship a signed binary build of the ZeroTier tap device driver, which can be installed on Mac with: + + sudo make install-mac-tap + +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*. ### Basic Troubleshooting For most users, it just works. -If you are running a local system firewall, we recommend adding a rules permitting zerotier. If you installed binaries for Windows this should be done automatically. Other platforms might require manual editing of local firewall rules depending on your configuration. +If you are running a local system firewall, we recommend adding a rule permitting UDP port 9993 inbound and outbound. If you installed binaries for Windows this should be done automatically. Other platforms might require manual editing of local firewall rules depending on your configuration. -See the [documentation site](https://docs.zerotier.com/zerotier/troubleshooting) for more information. +The Mac firewall can be found under "Security" in System Preferences. Linux has a variety of firewall configuration systems and tools. If you're using Ubuntu's *ufw*, you can do this: -The Mac firewall can be found under "Security" in System Preferences. Linux has a variety of firewall configuration systems and tools. + sudo ufw allow 9993/udp On CentOS check `/etc/sysconfig/iptables` for IPTables rules. For other distributions consult your distribution's documentation. You'll also have to check the UIs or documentation for commercial third party firewall applications like Little Snitch (Mac), McAfee Firewall Enterprise (Windows), etc. if you are running any of those. Some corporate environments might have centrally managed firewall software, so you might also have to contact IT. ZeroTier One peers will automatically locate each other and communicate directly over a local wired LAN *if UDP port 9993 inbound is open*. If that port is filtered, they won't be able to see each others' LAN announcement packets. If you're experiencing poor performance between devices on the same physical network, check their firewall settings. Without LAN auto-location peers must attempt "loopback" NAT traversal, which sometimes fails and in any case requires that every packet traverse your external router twice. -Users behind certain types of firewalls and "symmetric" NAT devices may not be 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. +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 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. -Additional help can be found in our [knowledge base](https://zerotier.atlassian.net/wiki/spaces/SD/overview). - -### Prometheus Metrics - -Prometheus Metrics are available at the `/metrics` API endpoint. This endpoint is protected by an API key stored in `metricstoken.secret` to prevent unwanted information leakage. Information that could be gleaned from the metrics include joined networks and peers your instance is talking to. - -Access control is via the ZeroTier control interface itself and `metricstoken.secret`. This can be sent as a bearer auth token, via the `X-ZT1-Auth` HTTP header field, or appended to the URL as `?auth=`. You can see the current metrics via `cURL` with the following command: - - // Linux - curl -H "X-ZT1-Auth: $(sudo cat /var/lib/zerotier-one/metricstoken.secret)" http://localhost:9993/metrics - - // macOS - curl -H "X-ZT1-Auth: $(sudo cat /Library/Application\ Support/ZeroTier/One/metricstoken.secret)" http://localhost:9993/metrics - - // Windows PowerShell (Admin) - Invoke-RestMethod -Headers @{'X-ZT1-Auth' = "$(Get-Content C:\ProgramData\ZeroTier\One\metricstoken.secret)"; } -Uri http://localhost:9993/metrics - -To configure a scrape job in Prometheus on the machine ZeroTier is running on, add this to your Prometheus `scrape_config`: - - - job_name: zerotier-one - honor_labels: true - scrape_interval: 15s - metrics_path: /metrics - static_configs: - - targets: - - 127.0.0.1:9993 - labels: - group: zerotier-one - node_id: $YOUR_10_CHARACTER_NODE_ID - authorization: - credentials: $YOUR_METRICS_TOKEN_SECRET - -If neither of these methods are desirable, it is probably possible to distribute metrics via [Prometheus Proxy](https://github.com/pambrose/prometheus-proxy) or some other tool. Note: We have not tested this internally, but will probably work with the correct configuration. - -Metrics are also available on disk in ZeroTier's working directory: - - // Linux - /var/lib/zerotier-one/metrics.prom - - // macOS - /Library/Application\ Support/ZeroTier/One/metrics.prom - - //Windows - C:\ProgramData\ZeroTier\One\metrics.prom - -#### Available Metrics - -| Metric Name | Labels | Metric Type | Description | -| --- | --- | --- | --- | -| zt_packet | packet_type, direction | Counter | ZeroTier packet type counts | -| zt_packet_error | error_type, direction | Counter | ZeroTier packet errors| -| zt_data | protocol, direction | Counter | number of bytes ZeroTier has transmitted or received | -| zt_num_networks | | Gauge | number of networks this instance is joined to | -| zt_network_multicast_groups_subscribed | network_id | Gauge | number of multicast groups networks are subscribed to | -| zt_network_packets | network_id, direction | Counter | number of incoming/outgoing packets per network | -| zt_peer_latency | node_id | Histogram | peer latency (ms) | -| zt_peer_path_count | node_id, status | Gauge | number of paths to peer | -| zt_peer_packets | node_id, direction | Counter | number of packets to/from a peer | -| zt_peer_packet_errors | node_id | Counter | number of incoming packet errors from a peer | - -If there are other metrics you'd like to see tracked, ask us in an Issue or send us a Pull Request! - -### HTTP / App server - -There is a static http file server suitable for hosting Single Page Apps at http://localhost:9993/app/ - -Use `zerotier-cli info -j` to find your zerotier-one service's homeDir - -``` sh -cd $ZT_HOME -sudo mkdir -p app/app1 -sudo mkdir -p app/appB -echo 'appA

hello world A' | sudo tee app/appA/index.html -echo 'app2

hello world 2' | sudo tee app/app2/index.html -curl -sL http://localhost:9993/app/appA http://localhost:9993/app/app2 -``` - -Then visit [http://localhost:9993/app/app1/](http://localhost:9993/app/app1/) and [http://localhost:9993/app/appB/](http://localhost:9993/app/appB/) - -Requests to paths don't exist return the app root index.html, as is customary for SPAs. -If you want, you can write some javascript that talks to the service or controller [api](https://docs.zerotier.com/service/v1). +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 72ca1f3b..2f3777b4 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,272 +1,6 @@ ZeroTier Release Notes ====== -# 2024-09-12 -- Version 1.14.1 - - * Multithreaded packet I/O support! Currently this is just for Linux and must - be enabled in local.conf. It will likely make the largest difference on small - multi-core devices where CPU is a bottleneck and high throughput is desired. - It may be enabled by default in the future but we want it to be thoroughly - tested. It's a little harder than it seems at first glance due to the need - to keep packets in sequence and balance load. - * Several multipath bug fixes. - * Updated the versions on a number of libraries related to OIDC support and HTTP. - * MacOS .app now shows the correct version in its Info.plist manifest. - * Sanitize MAC addresses in JSON format rules parser. - * Some basic information about the platform (OS, CPU architecture) is now reported - to network controllers when networks are joined so it can be displayed to - network admins and in the future used in policy checking and inventory operations. - -# 2024-05-02 -- Version 1.14.0 - - * Linux I/O performance improvements under heavy load - * Improvements to multipath - * Fix for port rebinding "coma" bug after periods offline (some laptop users) - * Fixed a rules engine quirk/ambiguity (GitHub Issue #2200) - * Controller API enhancements: node names and other node meta-data - * Other bug fixes - -# 2023-09-12 -- Version 1.12.2 - - * More improvements to macOS full tunnel mode. - * Faster recovery after changes to physical network settings. - -# 2023-08-25 -- Version 1.12.1 - - * Minor release to fix a port binding issue in Linux. - * Update Debian dependencies. - * No changes for other platforms. - -# 2023-08-23 -- Version 1.12.0 - - * Experimental Windows ARM64 support - * Fix numerous sleep/wake issues on macOS and other platforms - * Faster recovery after changes to physical network settings - * Prometheus compatible metrics support! - * Fix full tunnel mode on recent macOS versions - * Numerous macOS DNS fixes - * 10-30% speed improvement on Linux - -# 2023-03-23 -- Version 1.10.6 - - * Prevent binding temporary ipv6 addresses on macos (#1910) - * Prevent path-learning loops (#1914) - * Prevent infinite loop of UAC prompts in tray app - -# 2023-03-10 -- Version 1.10.5 - - * Fix for high CPU usage bug on Windows - -# 2023-03-07 -- Version 1.10.4 - - * SECURITY FIX (Windows): this version fixes a file permission problem on - Windows that could allow non-privileged users on a Windows system to read - privileged files in the ZeroTier service's working directory. This could - allow an unprivileged local Windows user to administrate the local ZeroTier - instance without appropriate local permissions. This issue is not remotely - exploitable unless a remote user can read arbitrary local files, and does - not impact other operating systems. - - * Fix a bug in the handling of multiple IP address assignments to virtual - interfaces on macOS. - -# 2023-02-15 -- Version 1.10.3 - - * Fix for duplicate paths in client. Could cause connectivity issues. Affects all platforms. - * Fix for Ethernet Tap MTU setting, would not properly apply on Linux. - * Fix default route bugs (macOS.) - * Enable Ping automatically for ZeroTier Adapters (Windows.) - * SSO updates and minor bugfixes. - * Add low-bandwidth mode. - * Add forceTcpRelay mode (optionally enabled.) - * Fix bug that prevented setting of custom TCP relay address. - * Build script improvements and bug fixes. - -# 2022-11-01 -- Version 1.10.2 - - * Fix another SSO "stuck client" issue in zeroidc. - * Expose root-reported external IP/port information via the local JSON API for better diagnostics. - * Multipath: CLI output improvement for inspecting bonds - * Multipath: balance-aware mode - * Multipath: Custom policies - * Multipath: Link quality measurement improvements - -Note that releases are coming few and far between because most of our dev effort is going into version 2. - -# 2022-06-27 -- Version 1.10.1 - - * Fix an issue that could cause SSO clients to get "stuck" on stale auth URLs. - * A few other SSO related bug fixes. - -# 2022-06-07 -- Version 1.10.0 - - * Fix formatting problem in `zerotier-cli` when using SSO networks. - * Fix a few other minor bugs in SSO signin to prepare for general availability. - * Remove requirement for webview in desktop UI and instead just make everything available via the tray pulldown/menu. Use [libui-ng](https://github.com/libui-ng/libui-ng) for minor prompt dialogs. Saves space and eliminates installation headaches on Windows. - * Fix SSO "spam" bug in desktop UI. - * Use system default browser for SSO login so all your plugins, MFA devices, password managers, etc. will work as you have them configured. - * Minor fix for bonding/multipath. - -# 2022-05-10 -- Version 1.8.10 - - * Fixed a bug preventing SSO sign-on on Windows. - -# 2022-04-25 -- Version 1.8.9 - - * Fixed a long-standing and strange bug that was causing sporadic "phantom" packet authentication failures. Not a security problem but could be behind sporadic reports of link failures under some conditions. - * Fixed a memory leak in SSO/OIDC support. - * Fixed SSO/OIDC display error on CLI. - * Fixed a bug causing nodes to sometimes fail to push certs to each other (primarily affects SSO/OIDC use cases). - * Fixed a deadlock bug on leaving SSO/OIDC managed networks. - * Added some new Linux distributions to the build subsystem. - -# 2022-04-11 -- Version 1.8.8 - - * Fix a local privilege escalation bug in the Windows installer. - * Dependency fix for some Ubuntu versions. - * No changes for other platforms. Windows upgrade recommended, everyone else optional. - -# 2022-03-30 -- Version 1.8.7 - - * Fix for dependency installations in Windows MSI package. - * Fix for desktop UI setup when run by a non-super-user. - * Bug fix in local OIDC / SSO support for auth0 and other providers. - * Other minor fixes for e.g. old Linux distributions. - -# 2022-03-04 -- Version 1.8.6 - - * Fixed an issue that could cause the UI to be non-responsive if not joined to any networks. - * Fix dependency issues in Debian and RedHat packages for some distributions (Fedora, Mint). - * Bumped the peer cache serialization version to prevent "coma" issues on upgrade due to changes in path logic behaving badly with old values. - -# 2022-02-22 -- Version 1.8.5 - - * Plumbing under the hood for endpoint device SSO support. - * Fix in LinuxEthernetTap to tap device support on very old (2.6) Linux kernels. - * Fix an issue that could cause self-hosted roots ("moons") to fail to assist peers in making direct links. (GitHub issue #1512) - * Merge a series of changes by Joseph Henry (of ZeroTier) that should fix some edge cases where ZeroTier would "forget" valid paths. - * Minor multipath improvements for automatic path negotiation. - -# 2021-11-30 -- Version 1.8.4 - - * Fixed an ugly font problem on some older macOS versions. - * Fixed a bug that could cause the desktop tray app control panel to stop opening after a while on Windows. - * Fixed a possible double "release" in macOS tray app code that crashed on older macOS versions. - * Fixed installation on 32-bit Windows 10. - * Fixed a build flags issue that could cause ZeroTier to crash on older ARM32 CPUs. - -# 2021-11-15 -- Version 1.8.3 - - * Remove problematic spinlock, which was only used on x86_64 anyway. Just use pthread always. - * Fix fd leak on MacOS that caused non-responsiveness after some time. - * Fix Debian install scripts to set /usr/sbin/nologin as shell on service user. - * Fix regression that could prevent managed routes from being deleted. - * DesktopUI: Remove NSDate:now() call, now works on MacOS 10.13 or newer! - -# 2021-11-08 -- Version 1.8.2 - - * Fix multicast on linux. - * Fix a bug that could cause the tap adapter to have the wrong MAC on Linux. - * Update build flags to possibly support MacOS older than 10.14, but more work needs to be done. It may not work yet. - * Fix path variable setting on Windows. - -# 2021-10-28 -- Version 1.8.1 - - * Fix numerous UI issues from 1.8.0 (never fully released). - * Remove support for REALLY ancient 1.1.6 or earlier network controllers. - * MacOS IPv6 no longer binds to temporary addresses as these can cause interruptions if they expire. - * Added additional hardening against address impersonation on networks (also in 1.6.6). - * Fix an issue that could cause clobbering of MacOS IP route settings on restart. - - * NOTE: Windows 7 is no longer supported! Windows 7 users will have to use version 1.6.5 or earlier. - -# 2021-09-15 -- Version 1.8.0 (preview release only) - - * A *completely* rewritten desktop UI for Mac and Windows! - * Implement a workaround for one potential source of a "coma" bug, which can occur if buggy NATs/routers stop allowing the service to communicate on a given port. ZeroTier now reassigns a new secondary port if it's offline for a while unless a secondary port is manually specified in local.conf. Working around crummy buggy routers is an ongoing effort. - * Fix for MacOS MTU capping issue on feth devices - * Fix for mistakenly using v6 source addresses for v4 routes on some platforms - * Stop binding to temporary IPv6 addresses - * Set MAC address before bringing up Linux TAP link - * Check if DNS servers need to be applied on macOS - * Upgrade json.hpp dependency to version 3.10.2 - -# 2021-09-21 -- Version 1.6.6 - - * Backport COM hash check mitigation against network member impersonation. - -# 2021-04-13 -- Version 1.6.5 - - * Fix a bug in potential network path filtering that could in some circumstances lead to "software laser" effects. - * Fix a printf overflow in zerotier-cli (not exploitable or a security risk) - * Windows now looks up the name of ZeroTier devices instead of relying on them having "ZeroTier" in them. - -# 2021-02-15 -- Version 1.6.4 - - * The groundhog saw his shadow, which meant that the "connection coma" bug still wasn't gone. We think we found it this time. - -# 2021-02-02 -- Version 1.6.3 - - * Likely fix for GitHub issue #1334, an issue that could cause ZeroTier to - go into a "coma" on some networks. - * Also groundhog day - -# 2020-11-30 -- Version 1.6.2 - - * Fix an ARM hardware AES crypto issue (not an exploitable vulnerability). - * Fix a Linux network leave hang due to a mutex deadlock. - -# 2020-11-24 -- Version 1.6.1 - -This release fixes some minor bugs and other issues in 1.6.0. - - * Fixed a bug that caused IP addresses in the 203.0.0.0/8 block to be miscategorized as not being in global scope. - * Changed Linux builds to (hopefully) fix LXC and SELinux issues. - * Fixed unaligned memory access that caused crash on FreeBSD systems on the ARM architecture. - * Merged CLI options for controlling bonded devices into the beta multipath code. - * Updated Windows driver with Microsoft cross-signing to fix issues on some Windows systems. - -# 2020-11-19 -- Version 1.6.0 - -Version 1.6.0 is a major release that incorporates back-ported features from the 2.0 branch, which is still under development. It also fixes a number of issues. - -New features and improvements (including those listed under 1.5.0): - - * **Apple Silicon** (MacOS ARM64) native support via universal binary. ZeroTier now requires the very latest Xcode to build. - * **Linux performance improvements** for up to 25% faster tun/tap I/O performance on multi-core systems. - * **Multipath support** with modes modeled after the Linux kernel's bonding driver. This includes active-passive and active-active modes with fast failover and load balancing. See section 2.1.5 of the manual. - * **DNS configuration** push from network controllers to end nodes, with locally configurable permissions for whether or not push is allowed. - * **AES-GMAC-SIV** encryption mode, which is both somewhat more secure and significantly faster than the old Salsa20/12-Poly1305 mode on hardware that supports AES acceleration. This includes virtually all X86-64 chips and most ARM64. This mode is based on AES-SIV and has been audited by Trail of Bits to ensure that it is equivalent security-wise. - -Bug fixes: - - * **Managed route assignment fixes** to eliminate missing routes on Linux and what we believe to be the source of sporadic high CPU usage on MacOS. - * **Hang on shutdown** issues should be fixed. - * **Sporadic multicast outages** should be fixed. - -Known remaining issues: - - * AES hardware acceleration is not yet supported on 32-bit ARM, PowerPC (32 or 64), or MIPS (32 or 64) systems. Currently supported are X86-64 and ARM64/AARCH64 with crypto extensions. - -# 2020-10-05 -- Version 1.5.0 (actually 1.6.0-beta1) - -Version 1.6.0 (1.5.0 is a beta!) is a significant release that incorporates a number of back-ported fixes and features from the ZeroTier 2.0 tree. - -Major new features are: - - * **Multipath support** with modes modeled after the Linux kernel's bonding driver. This includes active-passive and active-active modes with fast failover and load balancing. See section 2.1.5 of the manual. - * **DNS configuration** push from network controllers to end nodes, with locally configurable permissions for whether or not push is allowed. - * **AES-GMAC-SIV** encryption mode, which is both somewhat more secure and significantly faster than the old Salsa20/12-Poly1305 mode on hardware that supports AES acceleration. This includes virtually all X86-64 chips and most ARM64. This mode is based on AES-SIV and has been audited by Trail of Bits to ensure that it is equivalent security-wise. - -Known issues that are not yet fixed in this beta: - - * Some Mac users have reported periods of 100% CPU in kernel_task and connection instability after leaving networks that have been joined for a period of time, or needing to kill ZeroTier and restart it to finish leaving a network. This doesn't appear to affect all users and we haven't diagnosed the root cause yet. - * The service sometimes hangs on shutdown requiring a kill -9. This also does not affect all systems or users. - * AES hardware acceleration is not yet supported on 32-bit ARM, PowerPC (32 or 64), or MIPS (32 or 64) systems. Currently supported are X86-64 and ARM64/AARCH64 with crypto extensions. - * Some users have reported multicast/broadcast outages on networks lasting up to 30 seconds. Still investigating. - -We're trying to fix all these issues before the 1.6.0 release. Stay tuned. - # 2019-08-30 -- Version 1.4.6 * Update default root list to latest @@ -365,7 +99,7 @@ We're trying to fix all these issues before the 1.6.0 release. Stay tuned. # 2017-04-20 -- Version 1.2.4 * Managed routes are now only bifurcated for the default route. This is a change in behavior, though few people will probably notice. Bifurcating all managed routes was causing more trouble than it was worth for most users. - * Up to 2X crypto speedup on x86-64 (except Windows, which will take some porting) and 32-bit ARM platforms due to integration of fast assembly language implementations of Salsa20/12 from the [supercop](http://bench.cr.yp.to/supercop.html) code base. These were written by Daniel J. Bernstein and are in the public domain. My MacBook Pro (Core i5 2.8ghz) now does almost 1.5GiB/sec Salsa20/12 per core and a Raspberry Pi got a 2X boost. 64-bit ARM support and Windows support will take some work but should not be too hard. + * Up to 2X crypto speedup on x86-64 (except Windows, which will take some porting) and 32-bit ARM platforms due to integration of fast assembly language implementations of Salsa20/12 from the [supercop](http://bench.cr.yp.to/supercop.html) code base. These were written by Daniel J. Bernstein and are in the public domain. My Macbook Pro (Core i5 2.8ghz) now does almost 1.5GiB/sec Salsa20/12 per core and a Raspberry Pi got a 2X boost. 64-bit ARM support and Windows support will take some work but should not be too hard. * Refactored code that manages credentials to greatly reduce memory use in most cases. This may also result in a small performance improvement. * Reworked and simplified path selection and priority logic to fix path instability and dead path persistence edge cases. There have been some sporadic reports of persistent path instabilities and dead paths hanging around that take minutes to resolve. These have proven difficult to reproduce in house, but hopefully this will fix them. In any case it seems to speed up path establishment in our tests and it makes the code simpler and more readable. * Eliminated some unused cruft from the code around path management and in the peer class. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index c539ed6a..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,93 +0,0 @@ -# Security - -ZeroTier takes the security of our software products and services seriously, which -includes all source code repositories managed through our GitHub organization. - -## Supported Versions - -The following versions of ZeroTier One receive security updates - -| Version | Supported | -| -------- | ------------------ | -| 1.14.x | :white_check_mark: | -| 1.12.x | :white_check_mark: | -| < 1.12.0 | :x: | - -## Reporting a Vulnerability - -**Please do not report security issues through public GitHub issues** - -Instead, please report vulnerabilities via email to security@zerotier.com. If possible, -please encrypt with our PGP key (see below). - -Please include the following information, or as much as you can provide to help us -understand the nature and scope of the issue: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -## Preferred Languages - -We prefer all communications to be in English. - -## security@zerotier.com PGP key - -``` ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQINBGQGOVIBEACalXTnNqaiSOVLFEiqHpDMg8N/OI5D5850Xy1ZEvx3B3rz7cbn -k30ozHtJKbh+vqpyItE7DjyQAuF19gP5Q64Yh0Y+MmLHq60q/GwOwAYz7cI+UzA3 -5x8YqcmTp32LAM1xJn+iMlMLBuAmJl4kULKmOXPlpqPiyTFs5saizvm7fgRmfgJJ -HpsnIrTkaDFJhAR+jvMJohVYwmhuydeI0DsHu7KGpG1ddcHDrUjOPNqXnnAPSPwx -llw4yfKlQb8GYErsv/G5QVyzd5+SxEuiI4MARRnrk8LlMQ33CR6pzIQ/Bk5AAmye -mHqfEAknkiOf++urYhRs9BL3Kz3MdV0cg92zr9EFOg0u56jxf5OnAiTOhGUUA0hn -dS7peVGl46R9Oy2JYIazNDGi+4NIsYDFXsnsss9xOQVygPyeQd71zFHfix0jct9w -j3o/kj7Egsnm9nc13354bYT6bbalqXiRWwGH1eAFpjueNWiVFwZS6NZUP3WeNDiY -BlPo1LodvolbXiJcTILTCyEkERJPCK2zoE2nTdVfvTLWsuehw1M6Yd2/q74TVYy/ -RY+KjHkrChEBQ9PqXsXRHj6opKbT8JLfZkvU5k+3IiqqxOpB+QXFI/whj493CxWW -so7QAmzOCyJq8GDVPxzkwUac22YIkXdiOmb8i/HWq+kLY/HjQE259Gx6KwARAQAB -tClaZXJvVGllciBTZWN1cml0eSA8c2VjdXJpdHlAemVyb3RpZXIuY29tPokCTAQT -AQoANhYhBH1HQGb+4jzl6mnFqf09m6uqADkABQJkBjlSAhsDBAsJCAcEFQoJCAUW -AgMBAAIeAQIXgAAKCRD9PZurqgA5ACqPD/sFt6SG6Tu0HwTY2ofJtYsa2GBLL0pf -dYlX4cWSs1PVB5+m5Oj18y+GB2umA9GnsVtmvaSfp3XEngt2zNWX27uUsVfL35b2 -/5TVVe8RjzOedqMN+lQWMvO+f/C1zmWYXjjpC+iGjgMMaRRrofkkn+7uL4N9y6gY -rcXtpACT1rYFC+i1AKnZfUO8Vr5ji7odq0f7bDkN/N38rB0kRRwEmO8wqdpQK6gK -nxf9vgJl5ggimDk5Xtz1sfd3y28bf5N4hdOCkXUbd10nUFY3wDNTM4VxozxTGJeG -imdcc19Wuw/1fGUZ5SIjgPanCdPLGYwSTr+M6Fuern9uTtlC1GOby3BUtmVGP6EU -1pSAJSRpmoBPHKKOYtSMwV8PCboXru9P1ab8y8STKM3SKyghUJrl17gdc0LaksZa -E54pJudGPIQMFRqZjMdV6jgMuaLTozjZ4mW8EThf4mkX4xDkO8l7cOn0225ZYJZC -lZKpdnwzk9owkJA80u4KBNJxTtB4ZAPzjBsD5hFzCZQTLNQp/psU3EjZsau28eXT -E/C1QjEQHgy4ohkgQlCm1H1+clKssCWcdmsVGXuS1u8gh4K6X9b0Z6LeCGRaQvH2 -+DB8oTAdqp9nUZv9rP4pbo+sR4fF67CFLriVuxjedAiFkbM4uHMFcL4tc/X9+DRo -YN5X7oEkZvO507kCDQRkBjlSARAAz58UMF7K1qKyQjzKTcutaYZ5SaIGky9lCLZn -/2vjpFCoBogkxS/6IKQcwZk8b4S9QstaaQZDFEkxqNeKC0GiFTAMAb6SmYcK495h -EZnHl0NA5Nc2dBlZk5E/ENzTCz2bXaxCcVESc2z+xCzu07brbhGrqvliKiwOUzt9 -JzqEsar6I95OutBcZvkFCs44/Uf9bS1qf1w4klE8w3vdMtGH23umrET4tFZ+sh6o -ZFtQx0u2eKjsRdn/RMtsxLNaJlcE1DdIAqBpQrcmuwMC8v5wUGfCGZjhClzmyQlq -akUkayir7UtbHbFT/mgO+YI77YGXWk5QrwPscqqT2l8KB/YMujNDmaWa/0KV1lIY -zr5s4dzVeiwqFLR9ANFIhzFwzf3JLi6XSx123Qix0TxZoYPZCHl7yoi9qi6qybz5 -0Od2LSz3jbApeKYymZ+zjE+YV5y9DI6Wzy1j2M1FogNvTO9fMk+6dLt4HhTdSNvH -cKya462YCcy+tnZTkhmh+FTebbJlV6D4wG7skE5KCdBhjm53xLwp6XW9L6n2CrkL -W1IDBcCz0oPd1sMkXbO3wnxdXprV2XurCfsg/R2nszSNzvdJ8/xj3cr9hpoJ714R -qqyoEDRZ1Ss9kGL166o5MpN5qb/EewdkqGgWP7YFXbhsdHQiW7Z7dAqzjoaybD4O -nakkwyUAEQEAAYkCNgQYAQoAIBYhBH1HQGb+4jzl6mnFqf09m6uqADkABQJkBjlS -AhsMAAoJEP09m6uqADkAax0P/Rh8EZYRqW6dPYTl1YQusAK10rAcRNq3ekjofXGk -oXK1S7HWGoFgl5++5nfSfNgFJ5VLcgIM56wtIf49zFjWe5oC6fw8k+ghh4d2chMP -hdDILx6e0c30Iq1+EvovGR9hWa0wJ4cKTdzlwhY9ZC09q0ia+bl2mwpie1JQDR0c -zXCjt+PldLeeK9z1/XT0Q7KowYC+U18oR+KFm+EaRV4QT85JVequnIeGkmaHJrHB -lH4T5A5ib7y8edon1c0Zx3GsaxJUojkEJ0SX7ffVDu6ztUZfkHfCVpMW4VzUeGA/ -m+CtFO9ciLRGZEkRa+zhIGoBvwEXU0GiwiF4nZ0F2C8UioeW0YIEV9zl3nXJctYE -ZKc2whSENQRTGgaYHVoVZhznt71LKWgFLshwBo81UCXVkzwAjMW1ActDnmPw5M7q -xR5Qp5G49Z1GmfSozazha0HVFPKNV5i3RlTzs4yLUnZyH0yC9IvtOefMHcLjG96L -N5miEV97gvJJjrn8rhRvpUwAWgmT/9IuYjBNQTtNN40arto5HxezR76WCjdKYxdL -p3dM1iiBDShHNm7LdyZlLFhTOMU0tNBxJJ7B09ar5gakeZjD+2aB1ODX9VuFtozL -onBjI2gIkry0UIkuznHfFw05lZAZAiqHEVgVi/WTk4C/bklDZNgE0lx+IWzEz2iS -L455 -=lheL ------END PGP PUBLIC KEY BLOCK----- -``` diff --git a/attic/Binder.hpp b/attic/Binder.hpp new file mode 100644 index 00000000..67debc80 --- /dev/null +++ b/attic/Binder.hpp @@ -0,0 +1,461 @@ +/* + * 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. + */ +/****/ + +#ifndef ZT_BINDER_HPP +#define ZT_BINDER_HPP + +#include "../node/Constants.hpp" + +#include +#include +#include +#include + +#ifdef __WINDOWS__ +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#ifdef __LINUX__ +#include +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "../node/InetAddress.hpp" +#include "../node/Mutex.hpp" +#include "../node/Utils.hpp" + +#include "Phy.hpp" +#include "OSUtils.hpp" + +#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__)) +#define ZT_UDP_DESIRED_BUF_SIZE 1048576 +#else +#define ZT_UDP_DESIRED_BUF_SIZE 131072 +#endif + +// Period between refreshes of bindings +#define ZT_BINDER_REFRESH_PERIOD 30000 + +// Max number of bindings +#define ZT_BINDER_MAX_BINDINGS 256 + +namespace ZeroTier { + +/** + * Enumerates local devices and binds to all potential ZeroTier path endpoints + * + * This replaces binding to wildcard (0.0.0.0 and ::0) with explicit binding + * as part of the path to default gateway support. Under the hood it uses + * different queries on different OSes to enumerate devices, and also exposes + * device enumeration and endpoint IP data for use elsewhere. + * + * On OSes that do not support local port enumeration or where this is not + * meaningful, this degrades to binding to wildcard. + */ +class Binder +{ +private: + struct _Binding + { + _Binding() : udpSock((PhySocket *)0),tcpListenSock((PhySocket *)0) {} + PhySocket *udpSock; + PhySocket *tcpListenSock; + InetAddress address; + }; + +public: + Binder() : _bindingCount(0) {} + + /** + * Close all bound ports, should be called on shutdown + * + * @param phy Physical interface + */ + template + void closeAll(Phy &phy) + { + Mutex::Lock _l(_lock); + for(unsigned int b=0,c=_bindingCount;b template + * @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method + */ + template + void refresh(Phy &phy,unsigned int *ports,unsigned int portCount,const std::vector explicitBind,INTERFACE_CHECKER &ifChecker) + { + std::map localIfAddrs; + PhySocket *udps,*tcps; + Mutex::Lock _l(_lock); + bool interfacesEnumerated = true; + + if (explicitBind.empty()) { +#ifdef __WINDOWS__ + + char aabuf[32768]; + ULONG aalen = sizeof(aabuf); + if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast(aabuf),&aalen) == NO_ERROR) { + PIP_ADAPTER_ADDRESSES a = reinterpret_cast(aabuf); + while (a) { + PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress; + while (ua) { + InetAddress ip(ua->Address.lpSockaddr); + if (ifChecker.shouldBindInterface("",ip)) { + switch(ip.ipScope()) { + default: break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for(int x=0;x<(int)portCount;++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip,std::string())); + } + break; + } + } + ua = ua->Next; + } + a = a->Next; + } + } + else { + interfacesEnumerated = false; + } + +#else // not __WINDOWS__ + + /* On Linux we use an alternative method if available since getifaddrs() + * gets very slow when there are lots of network namespaces. This won't + * work unless /proc/PID/net/if_inet6 exists and it may not on some + * embedded systems, so revert to getifaddrs() there. */ + +#ifdef __LINUX__ + char fn[256],tmp[256]; + std::set ifnames; + const unsigned long pid = (unsigned long)getpid(); + + // Get all device names + OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid); + FILE *procf = fopen(fn,"r"); + if (procf) { + while (fgets(tmp,sizeof(tmp),procf)) { + tmp[255] = 0; + char *saveptr = (char *)0; + for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) { + if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0)) + ifnames.insert(f); + break; // we only want the first field + } + } + fclose(procf); + } + else { + interfacesEnumerated = false; + } + + // Get IPv6 addresses (and any device names we don't already know) + OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid); + procf = fopen(fn,"r"); + if (procf) { + while (fgets(tmp,sizeof(tmp),procf)) { + tmp[255] = 0; + char *saveptr = (char *)0; + unsigned char ipbits[16]; + memset(ipbits,0,sizeof(ipbits)); + char *devname = (char *)0; + int n = 0; + for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) { + switch(n++) { + case 0: // IP in hex + Utils::unhex(f,32,ipbits,16); + break; + case 5: // device name + devname = f; + break; + } + } + if (devname) { + ifnames.insert(devname); + InetAddress ip(ipbits,16,0); + if (ifChecker.shouldBindInterface(devname,ip)) { + switch(ip.ipScope()) { + default: break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for(int x=0;x<(int)portCount;++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip,std::string(devname))); + } + break; + } + } + } + } + fclose(procf); + } + + // Get IPv4 addresses for each device + if (ifnames.size() > 0) { + const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0); + struct ifconf configuration; + configuration.ifc_len = 0; + configuration.ifc_buf = nullptr; + + if (controlfd < 0) goto ip4_address_error; + if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error; + configuration.ifc_buf = (char*)malloc(configuration.ifc_len); + if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error; + + for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) { + struct ifreq& request = configuration.ifc_req[i]; + struct sockaddr* addr = &request.ifr_ifru.ifru_addr; + if (addr->sa_family != AF_INET) continue; + std::string ifname = request.ifr_ifrn.ifrn_name; + // name can either be just interface name or interface name followed by ':' and arbitrary label + if (ifname.find(':') != std::string::npos) + ifname = ifname.substr(0, ifname.find(':')); + + InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0); + if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) { + switch(ip.ipScope()) { + default: break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for(int x=0;x<(int)portCount;++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip,ifname)); + } + break; + } + } + } + + ip4_address_error: + free(configuration.ifc_buf); + if (controlfd > 0) close(controlfd); + } + + const bool gotViaProc = (localIfAddrs.size() > 0); +#else + const bool gotViaProc = false; +#endif +#if !defined(ZT_SDK) || !defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android + if (!gotViaProc) { + struct ifaddrs *ifatbl = (struct ifaddrs *)0; + struct ifaddrs *ifa; + if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) { + ifa = ifatbl; + while (ifa) { + if ((ifa->ifa_name)&&(ifa->ifa_addr)) { + InetAddress ip = *(ifa->ifa_addr); + if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) { + switch(ip.ipScope()) { + default: break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for(int x=0;x<(int)portCount;++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip,std::string(ifa->ifa_name))); + } + break; + } + } + } + ifa = ifa->ifa_next; + } + freeifaddrs(ifatbl); + } + else { + interfacesEnumerated = false; + } + } +#endif + +#endif + } else { + for(std::vector::const_iterator i(explicitBind.begin());i!=explicitBind.end();++i) + localIfAddrs.insert(std::pair(*i,std::string())); + } + + // Default to binding to wildcard if we can't enumerate addresses + if (!interfacesEnumerated && localIfAddrs.empty()) { + for(int x=0;x<(int)portCount;++x) { + localIfAddrs.insert(std::pair(InetAddress((uint32_t)0,ports[x]),std::string())); + localIfAddrs.insert(std::pair(InetAddress((const void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,ports[x]),std::string())); + } + } + + const unsigned int oldBindingCount = _bindingCount; + _bindingCount = 0; + + // Save bindings that are still valid, close those that are not + for(unsigned int b=0;b::const_iterator ii(localIfAddrs.begin());ii!=localIfAddrs.end();++ii) { + unsigned int bi = 0; + while (bi != _bindingCount) { + if (_bindings[bi].address == ii->first) + break; + ++bi; + } + if (bi == _bindingCount) { + udps = phy.udpBind(reinterpret_cast(&(ii->first)),(void *)0,ZT_UDP_DESIRED_BUF_SIZE); + tcps = phy.tcpListen(reinterpret_cast(&(ii->first)),(void *)0); + if ((udps)&&(tcps)) { +#ifdef __LINUX__ + // Bind Linux sockets to their device so routes that we manage do not override physical routes (wish all platforms had this!) + if (ii->second.length() > 0) { + char tmp[256]; + Utils::scopy(tmp,sizeof(tmp),ii->second.c_str()); + int fd = (int)Phy::getDescriptor(udps); + if (fd >= 0) + setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp)); + fd = (int)Phy::getDescriptor(tcps); + if (fd >= 0) + setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp)); + } +#endif // __LINUX__ + if (_bindingCount < ZT_BINDER_MAX_BINDINGS) { + _bindings[_bindingCount].udpSock = udps; + _bindings[_bindingCount].tcpListenSock = tcps; + _bindings[_bindingCount].address = ii->first; + phy.setIfName(udps,(char*)ii->second.c_str(),(int)ii->second.length()); + ++_bindingCount; + } + } else { + phy.close(udps,false); + phy.close(tcps,false); + } + } + } + } + + /** + * @return All currently bound local interface addresses + */ + inline std::vector allBoundLocalInterfaceAddresses() const + { + std::vector aa; + Mutex::Lock _l(_lock); + for(unsigned int b=0,c=_bindingCount;b + inline bool udpSendAll(Phy &phy,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) + { + bool r = false; + Mutex::Lock _l(_lock); + for(unsigned int b=0,c=_bindingCount;b _bindingCount; + Mutex _lock; +}; + +} // namespace ZeroTier + +#endif diff --git a/osdep/Http.cpp b/attic/Http.cpp similarity index 99% rename from osdep/Http.cpp rename to attic/Http.cpp index d392cd54..9ff1a068 100644 --- a/osdep/Http.cpp +++ b/attic/Http.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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/osdep/Http.hpp b/attic/Http.hpp similarity index 97% rename from osdep/Http.hpp rename to attic/Http.hpp index 6e669ab2..d9cad4dc 100644 --- a/osdep/Http.hpp +++ b/attic/Http.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -19,9 +19,9 @@ #include #if defined(_WIN32) || defined(_WIN64) -#include -#include -#include +#include +#include +#include #else #include #include diff --git a/osdep/Phy.hpp b/attic/Phy.hpp similarity index 90% rename from osdep/Phy.hpp rename to attic/Phy.hpp index 14cf92ca..d4934edf 100644 --- a/osdep/Phy.hpp +++ b/attic/Phy.hpp @@ -1,10 +1,10 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * 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: 2026-01-01 + * 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. @@ -23,9 +23,9 @@ #if defined(_WIN32) || defined(_WIN64) -#include -#include -#include +#include +#include +#include #define ZT_PHY_SOCKFD_TYPE SOCKET #define ZT_PHY_SOCKFD_NULL (INVALID_SOCKET) @@ -48,10 +48,9 @@ #include #include #include +#include #include -#include "../node/Metrics.hpp" - #if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) #ifndef IPV6_DONTFRAG #define IPV6_DONTFRAG 62 @@ -142,12 +141,12 @@ private: }; struct PhySocketImpl { - PhySocketImpl() {} + PhySocketImpl() { memset(ifname, 0, sizeof(ifname)); } PhySocketType type; ZT_PHY_SOCKFD_TYPE sock; void *uptr; // user-settable pointer - uint16_t localPort; ZT_PHY_SOCKADDR_STORAGE_TYPE saddr; // remote for TCP_OUT and TCP_IN, local for TCP_LISTEN, RAW, and UDP + char ifname[16]; }; std::list _socks; @@ -231,30 +230,76 @@ public: * @param s Socket object * @return Underlying OS-type (usually int or long) file descriptor associated with object */ - static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket* s) throw() - { - return reinterpret_cast(s)->sock; - } + static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket *s) throw() { return reinterpret_cast(s)->sock; } /** * @param s Socket object * @return Pointer to user object */ - static inline void** getuptr(PhySocket* s) throw() + static inline void** getuptr(PhySocket *s) throw() { return &(reinterpret_cast(s)->uptr); } + + /** + * @param s Socket object + * @param nameBuf Buffer to store name of interface which this Socket object is bound to + * @param buflen Length of buffer to copy name into + */ + static inline void getIfName(PhySocket *s, char *nameBuf, int buflen) { - return &(reinterpret_cast(s)->uptr); + if (s) { + memcpy(nameBuf, reinterpret_cast(s)->ifname, buflen); + } } /** - * Return the local port corresponding to this PhySocket + * @param s Socket object + * @param ifname Buffer containing name of interface that this Socket object is bound to + * @param len Length of name of interface + */ + static inline void setIfName(PhySocket *s, char *ifname, int len) + { + if (s) { + memcpy(&(reinterpret_cast(s)->ifname), ifname, len); + } + } + + /** + * Whether or not the socket object is in a closed state * * @param s Socket object - * - * @return Local port corresponding to this PhySocket + * @return true if socket is closed, false if otherwise */ - static inline uint16_t getLocalPort(PhySocket* s) throw() + inline bool isClosed(PhySocket *s) { - return reinterpret_cast(s)->localPort; + PhySocketImpl *sws = (reinterpret_cast(s)); + return sws->type == ZT_PHY_SOCKET_CLOSED; + } + + /** + * Get state of socket object + * + * @param s Socket object + * @return State of socket + */ + inline int getState(PhySocket *s) + { + PhySocketImpl *sws = (reinterpret_cast(s)); + return sws->type; + } + + /** + * In the event that this socket is erased, we need a way to convey to the multipath logic + * that this path is no longer valid. + * + * @param s Socket object + * @return Whether the state of this socket is within an acceptable range of values + */ + inline bool isValidState(PhySocket *s) + { + if (s) { + PhySocketImpl *sws = (reinterpret_cast(s)); + return sws->type >= ZT_PHY_SOCKET_CLOSED && sws->type <= ZT_PHY_SOCKET_UNIX_LISTEN; + } + return false; } /** @@ -266,27 +311,21 @@ public: inline void whack() { #if defined(_WIN32) || defined(_WIN64) - ::send(_whackSendSocket, (const char*)this, 1, 0); + ::send(_whackSendSocket,(const char *)this,1,0); #else - (void)(::write(_whackSendSocket, (PhySocket*)this, 1)); + (void)(::write(_whackSendSocket,(PhySocket *)this,1)); #endif } /** * @return Number of open sockets */ - inline unsigned long count() const throw() - { - return _socks.size(); - } + inline unsigned long count() const throw() { return _socks.size(); } /** * @return Maximum number of sockets allowed */ - inline unsigned long maxCount() const throw() - { - return ZT_PHY_MAX_SOCKETS; - } + inline unsigned long maxCount() const throw() { return ZT_PHY_MAX_SOCKETS; } /** * Wrap a raw file descriptor in a PhySocket structure @@ -353,14 +392,14 @@ public: int tmpbs = bs; if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) break; - bs -= 4096; + bs -= 16384; } bs = bufferSize; while (bs >= 65536) { int tmpbs = bs; if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) break; - bs -= 4096; + bs -= 16384; } } @@ -430,11 +469,6 @@ public: sws.type = ZT_PHY_SOCKET_UDP; sws.sock = s; sws.uptr = uptr; - -#ifdef __UNIX_LIKE__ - struct sockaddr_in *sin = (struct sockaddr_in *)localAddress; - sws.localPort = htons(sin->sin_port); -#endif memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); @@ -471,33 +505,11 @@ public: inline bool udpSend(PhySocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len) { PhySocketImpl &sws = *(reinterpret_cast(sock)); - bool sent = false; #if defined(_WIN32) || defined(_WIN64) - sent = ((long)::sendto( - sws.sock, - reinterpret_cast(data), - len, - 0, - remoteAddress, - (remoteAddress->sa_family == AF_INET6) ? - sizeof(struct sockaddr_in6) : - sizeof(struct sockaddr_in)) == (long)len); + return ((long)::sendto(sws.sock,reinterpret_cast(data),len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); #else - sent = ((long)::sendto( - sws.sock, - data, - len, - 0, - remoteAddress, - (remoteAddress->sa_family == AF_INET6) ? - sizeof(struct sockaddr_in6) : - sizeof(struct sockaddr_in)) == (long)len); + return ((long)::sendto(sws.sock,data,len,0,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); #endif - if (sent) { - Metrics::udp_send += len; - } - - return sent; } #ifdef __UNIX_LIKE__ @@ -1006,61 +1018,18 @@ public: break; case ZT_PHY_SOCKET_UDP: - if (FD_ISSET(s->sock, &rfds)) { -#if (defined(__linux__) || defined(linux) || defined(__linux)) && defined(MSG_WAITFORONE) -#define RECVMMSG_WINDOW_SIZE 128 -#define RECVMMSG_BUF_SIZE 1500 - iovec iovs[RECVMMSG_WINDOW_SIZE]; - uint8_t bufs[RECVMMSG_WINDOW_SIZE][RECVMMSG_BUF_SIZE]; - sockaddr_storage addrs[RECVMMSG_WINDOW_SIZE]; - memset(addrs, 0, sizeof(addrs)); - mmsghdr mm[RECVMMSG_WINDOW_SIZE]; - memset(mm, 0, sizeof(mm)); - for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) { - iovs[i].iov_base = (void*)bufs[i]; - iovs[i].iov_len = RECVMMSG_BUF_SIZE; - mm[i].msg_hdr.msg_name = (void*)&(addrs[i]); - mm[i].msg_hdr.msg_iov = &(iovs[i]); - mm[i].msg_hdr.msg_iovlen = 1; - } - for (int k = 0; k < 1024; ++k) { - for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) { - mm[i].msg_hdr.msg_namelen = sizeof(sockaddr_storage); - mm[i].msg_len = 0; - } - int received_count = recvmmsg(s->sock, mm, RECVMMSG_WINDOW_SIZE, MSG_WAITFORONE, nullptr); - if (received_count > 0) { - for (int i = 0; i < received_count; ++i) { - long n = (long)mm[i].msg_len; - if (n > 0) { - try { - _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&(addrs[i]), bufs[i], (unsigned long)n); - } - catch (...) { - } - } - } - } - else { - break; - } - } -#else - for (int k = 0; k < 1024; ++k) { - memset(&ss, 0, sizeof(ss)); + if (FD_ISSET(s->sock,&rfds)) { + for(int k=0;k<1024;++k) { + memset(&ss,0,sizeof(ss)); socklen_t slen = sizeof(ss); - long n = (long)::recvfrom(s->sock, buf, sizeof(buf), 0, (struct sockaddr*)&ss, &slen); + long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen); if (n > 0) { try { - _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&ss, (void*)buf, (unsigned long)n); - } - catch (...) { - } - } - else if (n < 0) + _handler->phyOnDatagram((PhySocket *)&(*s),&(s->uptr),(const struct sockaddr *)&(s->saddr),(const struct sockaddr *)&ss,(void *)buf,(unsigned long)n); + } catch ( ... ) {} + } else if (n < 0) break; } -#endif } break; diff --git a/attic/PortMapper-libnatpmp.c b/attic/PortMapper-libnatpmp.c new file mode 100644 index 00000000..5da85cba --- /dev/null +++ b/attic/PortMapper-libnatpmp.c @@ -0,0 +1,14 @@ +#define ENABLE_STRNATPMPERR +#define _BSD_SOURCE +#define _DEFAULT_SOURCE +#define _XOPEN_SOURCE 600 + +#ifdef __APPLE__ +#ifndef _DARWIN_C_SOURCE +#define _DARWIN_C_SOURCE +#endif +#endif + +#include "../ext/libnatpmp/getgateway.c" +#include "../ext/libnatpmp/wingettimeofday.c" +#include "../ext/libnatpmp/natpmp.c" diff --git a/attic/PortMapper-miniupnpc.c b/attic/PortMapper-miniupnpc.c new file mode 100644 index 00000000..8d28da10 --- /dev/null +++ b/attic/PortMapper-miniupnpc.c @@ -0,0 +1,41 @@ +#define MINIUPNP_STATICLIB +#define MINIUPNPC_SET_SOCKET_TIMEOUT +#define MINIUPNPC_GET_SRC_ADDR +#define _BSD_SOURCE +#define _DEFAULT_SOURCE +#define _XOPEN_SOURCE 600 +#define MINIUPNPC_VERSION_STRING "2.0" +#define UPNP_VERSION_STRING "UPnP/1.1" + +#ifdef __LINUX__ +#define OS_STRING "Linux" +#endif +#ifdef __APPLE__ +#define OS_STRING "Darwin" +#endif +#ifdef __WINDOWS__ +#define OS_STRING "Windows" +#endif +#ifndef OS_STRING +#define OS_STRING "ZeroTier" +#endif + +#ifdef __APPLE__ +#ifndef _DARWIN_C_SOURCE +#define _DARWIN_C_SOURCE +#endif +#endif + +#include "../ext/miniupnpc/connecthostport.c" +#include "../ext/miniupnpc/igd_desc_parse.c" +#include "../ext/miniupnpc/minisoap.c" +#include "../ext/miniupnpc/miniupnpc.c" +#include "../ext/miniupnpc/miniwget.c" +#include "../ext/miniupnpc/minixml.c" +#include "../ext/miniupnpc/portlistingparse.c" +#include "../ext/miniupnpc/receivedata.c" +#include "../ext/miniupnpc/upnpcommands.c" +#include "../ext/miniupnpc/upnpdev.c" +#include "../ext/miniupnpc/upnperrors.c" +#include "../ext/miniupnpc/upnpreplyparse.c" +#include "../ext/miniupnpc/minissdpc.c" diff --git a/osdep/PortMapper.cpp b/attic/PortMapper.cpp similarity index 75% rename from osdep/PortMapper.cpp rename to attic/PortMapper.cpp index 49e88c8a..d0ed87c3 100644 --- a/osdep/PortMapper.cpp +++ b/attic/PortMapper.cpp @@ -4,15 +4,13 @@ * 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: 2026-01-01 + * 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. */ /****/ -#ifdef ZT_USE_MINIUPNPC - // Uncomment to dump debug messages //#define ZT_PORTMAPPER_TRACE 1 @@ -47,9 +45,14 @@ #include #include #else +#ifdef __ANDROID__ +#include "miniupnpc.h" +#include "upnpcommands.h" +#else #include "../ext/miniupnpc/miniupnpc.h" #include "../ext/miniupnpc/upnpcommands.h" #endif +#endif #ifdef ZT_USE_SYSTEM_NATPMP #include @@ -79,7 +82,6 @@ public: throw() { int mode = 0; // 0 == NAT-PMP, 1 == UPnP - int retrytime = 500; #ifdef ZT_PORTMAPPER_TRACE fprintf(stderr,"PortMapper: started for UDP port %d" ZT_EOL_S,localPort); @@ -87,26 +89,6 @@ public: while (run) { - { - // use initnatpmp to check if we can bind a port at all - natpmp_t _natpmp; - int result = initnatpmp(&_natpmp,0,0); - if (result == NATPMP_ERR_CANNOTGETGATEWAY || result == NATPMP_ERR_SOCKETERROR) { - closenatpmp(&_natpmp); -#ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: init failed %d. You might not have an internet connection yet. Trying again in %d" ZT_EOL_S, result, retrytime); -#endif - Thread::sleep(retrytime); - retrytime = retrytime * 2; - if (retrytime > ZT_PORTMAPPER_REFRESH_DELAY / 10) { - retrytime = ZT_PORTMAPPER_REFRESH_DELAY / 10; - } - continue; - } else { - closenatpmp(&_natpmp); - retrytime = 500; - } - } // --------------------------------------------------------------------- // NAT-PMP mode (preferred) // --------------------------------------------------------------------- @@ -128,7 +110,7 @@ public: mode = 1; closenatpmp(&natpmp); #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S); + PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S); #endif break; } @@ -151,7 +133,7 @@ public: publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0); } else { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S); + PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S); #endif closenatpmp(&natpmp); break; @@ -173,8 +155,8 @@ public: if (r == 0) { publicAddress.setPort(response.pnu.newportmapping.mappedpublicport); #ifdef ZT_PORTMAPPER_TRACE - char paddr[128]; - PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr)); + char paddr[128]; + PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr)); #endif Mutex::Lock sl(surface_l); surface.clear(); @@ -191,9 +173,8 @@ public: if (!natPmpSuccess) { mode = 1; #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S); + PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S); #endif - continue; } } // --------------------------------------------------------------------- @@ -217,7 +198,7 @@ public: { UPNPDev *dev = devlist; while (dev) { - PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st); + PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st); dev = dev->pNext; } } @@ -229,14 +210,13 @@ public: memset(&data,0,sizeof(data)); OSUtils::ztsnprintf(inport,sizeof(inport),"%d",localPort); - int foundValidIGD = 0; - if ((foundValidIGD = UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) { + if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S,lanaddr); + PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S,lanaddr); #endif if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip); + PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip); #endif for(int tries=0;tries<60;++tries) { @@ -262,7 +242,7 @@ public: memset(haveLeaseDuration,0,sizeof(haveLeaseDuration)); if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport); + PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport); #endif Mutex::Lock sl(surface_l); surface.clear(); @@ -277,7 +257,7 @@ public: int mapResult = 0; if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport); + PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport); #endif Mutex::Lock sl(surface_l); surface.clear(); @@ -287,7 +267,7 @@ public: break; } else { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult); + PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult); #endif Thread::sleep(1000); } @@ -296,31 +276,29 @@ public: } else { mode = 0; #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S); + PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S); #endif } } else { mode = 0; #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S); + PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S); #endif } + freeUPNPDevlist(devlist); - if(foundValidIGD) { - FreeUPNPUrls(&urls); - } } else { mode = 0; #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError); + PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError); #endif } } // --------------------------------------------------------------------- #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY); + PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY); #endif Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY); } @@ -354,5 +332,3 @@ std::vector PortMapper::get() const } } // namespace ZeroTier - -#endif // ZT_USE_MINIUPNPC diff --git a/osdep/PortMapper.hpp b/attic/PortMapper.hpp similarity index 90% rename from osdep/PortMapper.hpp rename to attic/PortMapper.hpp index c74df0c1..54b04de1 100644 --- a/osdep/PortMapper.hpp +++ b/attic/PortMapper.hpp @@ -4,15 +4,13 @@ * 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: 2026-01-01 + * 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. */ /****/ -#ifdef ZT_USE_MINIUPNPC - #ifndef ZT_PORTMAPPER_HPP #define ZT_PORTMAPPER_HPP @@ -26,7 +24,7 @@ /** * How frequently should we refresh our UPNP/NAT-PnP/whatever state? */ -#define ZT_PORTMAPPER_REFRESH_DELAY 300000 +#define ZT_PORTMAPPER_REFRESH_DELAY 120000 namespace ZeroTier { @@ -62,5 +60,3 @@ private: } // namespace ZeroTier #endif - -#endif // ZT_USE_MINIUPNPC diff --git a/attic/Root.hpp b/attic/Root.hpp new file mode 100644 index 00000000..c526007d --- /dev/null +++ b/attic/Root.hpp @@ -0,0 +1,182 @@ +/* + * 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. + */ +/****/ + +#ifndef ZT_ROOT_HPP +#define ZT_ROOT_HPP + +#include "Constants.hpp" +#include "Str.hpp" +#include "ECC384.hpp" +#include "Locator.hpp" +#include "InetAddress.hpp" +#include "Utils.hpp" +#include "Identity.hpp" +#include "Mutex.hpp" + +namespace ZeroTier { + +/** + * A root entry pointing to a node capable of global identity lookup and indirect transit + * + * Root entries point to DNS records that contain TXT entries that decode to Locator objects + * pointing to actual root nodes. A default root identity and static addresses can also be + * provided as fallback if DNS is not available. + * + * Note that root identities can change if DNS returns a different result, but that DNS entries + * are authenticated using their own signature scheme. This allows a root DNS name to serve + * up different roots based on factors like location or relative load of different roots. + * + * It's also possible to create a root with no DNS and no DNS validator public key. This root + * will be a static entry pointing to a single root identity and set of physical addresses. + */ +class Root +{ +public: + ZT_ALWAYS_INLINE Root() : _dnsPublicKeySize(0) {} + + /** + * Create a new root entry + * + * @param dn DNS name + * @param dnspk DNS public key for record validation + * @param dnspksize Size of DNS public key (currently always the size of a NIST P-384 point compressed public key) + * @param dflId Default identity if DNS is not available + * @param dflAddrs Default IP addresses if DNS is not available + */ + template + ZT_ALWAYS_INLINE Root(S dn,const uint8_t *const dnspk,const unsigned int dnspksize,const Identity &dflId,const std::vector &dflAddrs) : + _defaultIdentity(dflId), + _defaultAddresses(dflAddrs), + _dnsName(dn), + _dnsPublicKeySize(dnspksize) + { + if (dnspksize != 0) { + if (dnspksize > sizeof(_dnsPublicKey)) + throw ZT_EXCEPTION_INVALID_ARGUMENT; + memcpy(_dnsPublicKey,dnspk,dnspksize); + } + } + + /** + * @return Current identity (either default or latest locator) + */ + ZT_ALWAYS_INLINE const Identity id() const + { + if (_lastFetchedLocator.id()) + return _lastFetchedLocator.id(); + return _defaultIdentity; + } + + /** + * @param id Identity to check + * @return True if identity equals this root's current identity + */ + ZT_ALWAYS_INLINE bool is(const Identity &id) const + { + return ((_lastFetchedLocator.id()) ? (id == _lastFetchedLocator.id()) : (id == _defaultIdentity)); + } + + /** + * @return Current ZeroTier address (either default or latest locator) + */ + ZT_ALWAYS_INLINE const Address address() const + { + if (_lastFetchedLocator.id()) + return _lastFetchedLocator.id().address(); + return _defaultIdentity.address(); + } + + /** + * @return DNS name for this root or empty string if static entry with no DNS + */ + ZT_ALWAYS_INLINE const Str dnsName() const { return _dnsName; } + + /** + * @return Latest locator or NIL locator object if none + */ + ZT_ALWAYS_INLINE Locator locator() const { return _lastFetchedLocator; } + + /** + * @return Timestamp of latest retrieved locator or 0 if none + */ + ZT_ALWAYS_INLINE int64_t locatorTimestamp() const { return _lastFetchedLocator.timestamp(); } + + /** + * Update locator, returning true if new locator is valid and newer than existing + */ + ZT_ALWAYS_INLINE bool updateLocator(const Locator &loc) + { + if (!loc.verify()) + return false; + if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) { + _lastFetchedLocator = loc; + return true; + } + return false; + } + + /** + * Update this root's locator from a series of TXT records + */ + template + ZT_ALWAYS_INLINE bool updateLocatorFromTxt(I start,I end) + { + try { + if (_dnsPublicKeySize != ZT_ECC384_PUBLIC_KEY_SIZE) + return false; + Locator loc; + if (!loc.decodeTxtRecords(start,end,_dnsPublicKey)) // also does verify() + return false; + if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) { + _lastFetchedLocator = loc; + return true; + } + return false; + } catch ( ... ) {} + return false; + } + + /** + * Pick a random physical IP for this root with the given address family + * + * @param addressFamily AF_INET or AF_INET6 + * @return Address or InetAddress::NIL if no addresses exist for the given family + */ + ZT_ALWAYS_INLINE const InetAddress &pickPhysical(const int addressFamily) const + { + std::vector pickList; + const std::vector *const av = (_lastFetchedLocator) ? &(_lastFetchedLocator.phy()) : &_defaultAddresses; + for(std::vector::const_iterator i(av->begin());i!=av->end();++i) { + if (addressFamily == (int)i->ss_family) { + pickList.push_back(&(*i)); + } + } + if (pickList.size() == 1) + return *pickList[0]; + else if (pickList.size() > 1) + return *pickList[(unsigned long)Utils::random() % (unsigned long)pickList.size()]; + return InetAddress::NIL; + } + +private: + Identity _defaultIdentity; + std::vector _defaultAddresses; + Str _dnsName; + Locator _lastFetchedLocator; + unsigned int _dnsPublicKeySize; + uint8_t _dnsPublicKey[ZT_ECC384_PUBLIC_KEY_SIZE]; +}; + +} // namespace ZeroTier + +#endif diff --git a/cycle_controllers.sh b/attic/cycle_controllers.sh similarity index 100% rename from cycle_controllers.sh rename to attic/cycle_controllers.sh diff --git a/ext/misc/linux-old-glibc-compat.c b/attic/linux-old-glibc-compat.c similarity index 100% rename from ext/misc/linux-old-glibc-compat.c rename to attic/linux-old-glibc-compat.c diff --git a/attic/listaddrinfo.go b/attic/listaddrinfo.go new file mode 100644 index 00000000..3db54bf0 --- /dev/null +++ b/attic/listaddrinfo.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "net" +) + +func main() { + ifs, err := net.Interfaces() + if err != nil { + fmt.Printf("Error: %s\n", err.Error()) + return + } + for _, i := range ifs { + fmt.Printf("name: %s\n", i.Name) + fmt.Printf("hwaddr: %s\n", i.HardwareAddr.String()) + fmt.Printf("index: %d\n", i.Index) + fmt.Printf("addrs:\n") + addrs, _ := i.Addrs() + for _, a := range addrs { + fmt.Printf(" %s\n", a.String()) + } + fmt.Printf("multicast:\n") + mc, _ := i.MulticastAddrs() + for _, m := range mc { + fmt.Printf(" %s\n", m.String()) + } + fmt.Printf("\n") + } +} diff --git a/attic/macui/ZeroTier One.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/attic/macui/ZeroTier One.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/attic/macui/ZeroTier One.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/attic/macui/ZeroTier One/ZeroTier One.entitlements b/attic/macui/ZeroTier One/ZeroTier One.entitlements deleted file mode 100644 index 0c67376e..00000000 --- a/attic/macui/ZeroTier One/ZeroTier One.entitlements +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/make-bsd.mk b/attic/make-bsd.mk similarity index 70% rename from make-bsd.mk rename to attic/make-bsd.mk index ce0b4dde..8c7a6ad2 100644 --- a/make-bsd.mk +++ b/attic/make-bsd.mk @@ -1,42 +1,19 @@ # This requires GNU make, which is typically "gmake" on BSD systems -INCLUDES=-isystem ext -Iext/prometheus-cpp-lite-1.0/core/include -Iext/prometheus-cpp-lite-1.0/simpleapi/include +INCLUDES= DEFS= LIBS= include objects.mk ONE_OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o -ifeq ($(OSTYPE),FreeBSD) - # Auto-detect miniupnpc and nat-pmp as well and use ports libs if present, - # otherwise build into binary as done on Mac and Windows. - INCLUDES+=-I/usr/local/include - LIBS+=-L/usr/local/lib - ONE_OBJS+=osdep/PortMapper.o - override DEFS+=-DZT_USE_MINIUPNPC - MINIUPNPC_IS_NEW_ENOUGH=$(shell grep -sqr '.*define.*MINIUPNPC_VERSION.*"2..*"' /usr/local/include/miniupnpc/miniupnpc.h && echo 1) - ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1) - LIBS+=-lminiupnpc - override DEFS+=-DZT_USE_SYSTEM_MINIUPNPC - else - override DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"FreeBSD/$(shell uname -r)\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR - ONE_OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o - endif - ifeq ($(wildcard /usr/local/include/natpmp.h),) - ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o - else - LIBS+=-lnatpmp - override DEFS+=-DZT_USE_SYSTEM_NATPMP - endif -endif - # Build with address sanitization library for advanced debugging (clang) ifeq ($(ZT_SANITIZE),1) SANFLAGS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 endif # "make debug" is a shortcut for this ifeq ($(ZT_DEBUG),1) - CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) + CFLAGS+=-Wall -Werror -g -pthread $(INCLUDES) $(DEFS) LDFLAGS+= STRIP=echo ZT_TRACE=1 @@ -88,7 +65,7 @@ ifeq ($(CC_MACH),armhf) endif ifeq ($(CC_MACH),armv6) ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_NO_UNALIGNED_ACCESS + override DEFS+=-DZT_NO_TYPE_PUNNING ZT_USE_ARM32_NEON_ASM_SALSA2012=1 endif ifeq ($(CC_MACH),armv6zk) @@ -103,16 +80,16 @@ ifeq ($(CC_MACH),armv6kz) endif ifeq ($(CC_MACH),armv7) ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_AES_NO_ACCEL -DZT_NO_UNALIGNED_ACCESS + override DEFS+=-DZT_NO_TYPE_PUNNING ZT_USE_ARM32_NEON_ASM_SALSA2012=1 endif ifeq ($(CC_MACH),arm64) ZT_ARCHITECTURE=4 - override DEFS+=-DZT_NO_TYPE_PUNNING -march=armv8-a+crypto + override DEFS+=-DZT_NO_TYPE_PUNNING endif ifeq ($(CC_MACH),aarch64) ZT_ARCHITECTURE=4 - override DEFS+=-DZT_NO_TYPE_PUNNING -march=armv8-a+crypto + override DEFS+=-DZT_NO_TYPE_PUNNING endif ifeq ($(CC_MACH),mipsel) ZT_ARCHITECTURE=5 @@ -133,7 +110,7 @@ endif # Fail if system architecture could not be determined ifeq ($(ZT_ARCHITECTURE),999) -ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $(CC_MACH)) +ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $CC_MACH) .PHONY: err err: ; $(ERR) endif @@ -147,12 +124,11 @@ ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1) override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012 override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o override ASFLAGS+=-meabi=5 - override LDFLAGS+=-Wl,-z,notext endif override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" -CXXFLAGS+=$(CFLAGS) -std=c++17 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1 +CXXFLAGS+=$(CFLAGS) -std=c++11 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1 all: one diff --git a/make-linux.mk b/attic/make-linux.mk similarity index 63% rename from make-linux.mk rename to attic/make-linux.mk index efc1badf..9fd4f7b9 100644 --- a/make-linux.mk +++ b/attic/make-linux.mk @@ -1,25 +1,24 @@ # 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) - CC:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/gcc ]; then echo /opt/rh/devtoolset-8/root/usr/bin/gcc; else echo $(CC); fi) + CC:=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) + CC:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/gcc ]; then echo /opt/rh/devtoolset-8/root/usr/bin/gcc; else echo $(CC); fi) endif ifeq ($(origin CXX),default) - CXX:=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) - CXX:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/g++ ]; then echo /opt/rh/devtoolset-8/root/usr/bin/g++; else echo $(CXX); fi) + CXX:=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) + CXX:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/g++ ]; then echo /opt/rh/devtoolset-8/root/usr/bin/g++; else echo $(CXX); fi) endif -INCLUDES?=-Irustybits/target -isystem ext -Iext/prometheus-cpp-lite-1.0/core/include -Iext-prometheus-cpp-lite-1.0/3rdparty/http-client-lite/include -Iext/prometheus-cpp-lite-1.0/simpleapi/include +INCLUDES?= DEFS?= LDLIBS?= DESTDIR?= -EXTRA_DEPS?= include objects.mk ONE_OBJS+=osdep/LinuxEthernetTap.o ONE_OBJS+=osdep/LinuxNetLink.o -# for central controller buildsk +# for central controller builds TIMESTAMP=$(shell date +"%Y%m%d%H%M") # Auto-detect miniupnpc and nat-pmp as well and use system libs if present, @@ -32,7 +31,7 @@ ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1) override DEFS+=-DZT_USE_SYSTEM_MINIUPNPC LDLIBS+=-lminiupnpc else - override DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING="\"Linux\"" -DMINIUPNPC_VERSION_STRING="\"2.0\"" -DUPNP_VERSION_STRING="\"UPnP/1.1\"" -DENABLE_STRNATPMPERR + override DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR ONE_OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o endif ifeq ($(wildcard /usr/include/natpmp.h),) @@ -46,47 +45,51 @@ endif # Trying to use dynamically linked libhttp-parser causes tons of compatibility problems. ONE_OBJS+=ext/http-parser/http_parser.o +# Build with address sanitization library for advanced debugging (clang) +ifeq ($(ZT_SANITIZE),1) + DEFS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 +endif +ifeq ($(ZT_DEBUG_TRACE),1) + DEFS+=-DZT_DEBUG_TRACE +endif +ifeq ($(ZT_TRACE),1) + DEFS+=-DZT_TRACE +endif + ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1) override DEFS+=-DZT_RULES_ENGINE_DEBUGGING endif -ifeq ($(ZT_DEBUG_TRACE),1) - DEFS+=-DZT_DEBUG_TRACE -endif - # Build with address sanitization library for advanced debugging (clang) ifeq ($(ZT_SANITIZE),1) - override DEFS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 + SANFLAGS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 endif ifeq ($(ZT_DEBUG),1) - override CFLAGS+=-Wall -Wno-deprecated -g -O -pthread $(INCLUDES) $(DEFS) - override CXXFLAGS+=-Wall -Wno-deprecated -g -O -std=c++17 -pthread $(INCLUDES) $(DEFS) + override CFLAGS+=-Wall -Wno-deprecated -g -pthread $(INCLUDES) $(DEFS) + override CXXFLAGS+=-Wall -Wno-deprecated -g -std=c++11 -pthread $(INCLUDES) $(DEFS) ZT_TRACE=1 - ZT_CARGO_FLAGS= + STRIP?=echo # The following line enables optimization for the crypto code, since # C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box! node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CXXFLAGS=-Wall -O2 -g -pthread $(INCLUDES) $(DEFS) else - CFLAGS?=-O3 -fstack-protector + CFLAGS?=-O3 -fstack-protector -fPIE override CFLAGS+=-Wall -Wno-deprecated -pthread $(INCLUDES) -DNDEBUG $(DEFS) - CXXFLAGS?=-O3 -fstack-protector - override CXXFLAGS+=-Wall -Wno-deprecated -std=c++17 -pthread $(INCLUDES) -DNDEBUG $(DEFS) - LDFLAGS?=-pie -Wl,-z,relro,-z,now - ZT_CARGO_FLAGS=--release + CXXFLAGS?=-O3 -fstack-protector -fPIE + override CXXFLAGS+=-Wall -Wno-deprecated -std=c++11 -pthread $(INCLUDES) -DNDEBUG $(DEFS) + LDFLAGS=-pie -Wl,-z,relro,-z,now + STRIP?=strip + STRIP+=--strip-all endif ifeq ($(ZT_QNAP), 1) - override DEFS+=-D__QNAP__ - ZT_EMBEDDED=1 -endif -ifeq ($(ZT_UBIQUITI), 1) - override DEFS+=-D__UBIQUITI__ - ZT_EMBEDDED=1 + override DEFS+=-D__QNAP__ endif ifeq ($(ZT_SYNOLOGY), 1) + override CFLAGS+=-fPIC + override CXXFLAGS+=-fPIC override DEFS+=-D__SYNOLOGY__ - ZT_EMBEDDED=1 endif ifeq ($(ZT_DISABLE_COMPRESSION), 1) @@ -97,10 +100,6 @@ ifeq ($(ZT_TRACE),1) override DEFS+=-DZT_TRACE endif -ifeq ($(ZT_DEBUG),1) - override DEFS+=-DZT_DEBUG -endif - ifeq ($(ZT_USE_TEST_TAP),1) override DEFS+=-DZT_USE_TEST_TAP endif @@ -110,6 +109,12 @@ ifeq ($(ZT_VAULT_SUPPORT),1) override LDLIBS+=-lcurl endif +# Uncomment for gprof profile build +#CFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) +#CXXFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) +#LDFLAGS= +#STRIP=echo + # Determine system build architecture from compiler target CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) ZT_ARCHITECTURE=999 @@ -117,23 +122,11 @@ ifeq ($(CC_MACH),x86_64) ZT_ARCHITECTURE=2 ZT_USE_X64_ASM_SALSA=1 ZT_USE_X64_ASM_ED25519=1 - override CFLAGS+=-msse -msse2 - override CXXFLAGS+=-msse -msse2 - ZT_SSO_SUPPORTED=1 - ifeq ($(ZT_CONTROLLER),1) - EXT_ARCH=amd64 - endif endif ifeq ($(CC_MACH),amd64) ZT_ARCHITECTURE=2 ZT_USE_X64_ASM_SALSA=1 ZT_USE_X64_ASM_ED25519=1 - override CFLAGS+=-msse -msse2 - override CXXFLAGS+=-msse -msse2 - ZT_SSO_SUPPORTED=1 - ifeq ($(ZT_CONTROLLER),1) - EXT_ARCH=amd64 - endif endif ifeq ($(CC_MACH),powerpc64le) ZT_ARCHITECTURE=8 @@ -150,27 +143,17 @@ endif ifeq ($(CC_MACH),ppc64el) ZT_ARCHITECTURE=8 endif -ifeq ($(CC_MACH),e2k) - ZT_ARCHITECTURE=2 -endif -ifeq ($(CC_MACH),e2k64) - ZT_ARCHITECTURE=2 -endif ifeq ($(CC_MACH),i386) ZT_ARCHITECTURE=1 - ZT_SSO_SUPPORTED=1 endif ifeq ($(CC_MACH),i486) ZT_ARCHITECTURE=1 - ZT_SSO_SUPPORTED=1 endif ifeq ($(CC_MACH),i586) ZT_ARCHITECTURE=1 - ZT_SSO_SUPPORTED=1 endif ifeq ($(CC_MACH),i686) ZT_ARCHITECTURE=1 - ZT_SSO_SUPPORTED=1 endif ifeq ($(CC_MACH),arm) ZT_ARCHITECTURE=3 @@ -186,7 +169,6 @@ ifeq ($(CC_MACH),armhf) ZT_ARCHITECTURE=3 override DEFS+=-DZT_NO_TYPE_PUNNING ZT_USE_ARM32_NEON_ASM_CRYPTO=1 - ZT_SSO_SUPPORTED=1 endif ifeq ($(CC_MACH),armv6) ZT_ARCHITECTURE=3 @@ -208,11 +190,6 @@ ifeq ($(CC_MACH),armv6kz) override DEFS+=-DZT_NO_TYPE_PUNNING ZT_USE_ARM32_NEON_ASM_CRYPTO=1 endif -ifeq ($(CC_MACH),armv6k) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif ifeq ($(CC_MACH),armv7) ZT_ARCHITECTURE=3 override DEFS+=-DZT_NO_TYPE_PUNNING @@ -228,25 +205,13 @@ ifeq ($(CC_MACH),armv7hl) override DEFS+=-DZT_NO_TYPE_PUNNING ZT_USE_ARM32_NEON_ASM_CRYPTO=1 endif -ifeq ($(CC_MACH),armv7ve) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif ifeq ($(CC_MACH),arm64) ZT_ARCHITECTURE=4 - ZT_SSO_SUPPORTED=1 - ZT_USE_X64_ASM_ED25519=0 - override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON -march=armv8-a+crypto -mtune=generic -mstrict-align + override DEFS+=-DZT_NO_TYPE_PUNNING endif ifeq ($(CC_MACH),aarch64) ZT_ARCHITECTURE=4 - ZT_SSO_SUPPORTED=1 - ZT_USE_X64_ASM_ED25519=0 - override DEFS+=-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON -march=armv8-a+crypto -mtune=generic -mstrict-align - ifeq ($(ZT_CONTROLLER),1) - EXT_ARCH=arm64 - endif + override DEFS+=-DZT_NO_TYPE_PUNNING endif ifeq ($(CC_MACH),mipsel) ZT_ARCHITECTURE=5 @@ -267,42 +232,14 @@ endif ifeq ($(CC_MACH),s390x) ZT_ARCHITECTURE=16 endif -ifeq ($(CC_MACH),riscv64) - ZT_ARCHITECTURE=0 -endif -ifeq ($(CC_MACH),loongarch64) - ZT_ARCHITECTURE=17 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif # Fail if system architecture could not be determined ifeq ($(ZT_ARCHITECTURE),999) -ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $(CC_MACH)) +ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $CC_MACH) .PHONY: err err: ; $(ERR) endif -# Flag for Intel 32-bit processors since some machine images are incorrectly marked as i386 -ifeq ($(ZT_IA32),1) - override LDFLAGS+=-m32 - override CFLAGS+=-m32 - override CXXFLAGS+=-m32 - # Prevent the use of X64 crypto - ZT_USE_X64_ASM_SALSA=0 - ZT_USE_X64_ASM_ED25519=0 -endif - -ifeq ($(ZT_SSO_SUPPORTED), 1) - ifeq ($(ZT_EMBEDDED),) - override DEFS+=-DZT_SSO_SUPPORTED=1 - ifeq ($(ZT_DEBUG),1) - LDLIBS+=rustybits/target/debug/libzeroidc.a -ldl -lssl -lcrypto - else - LDLIBS+=rustybits/target/release/libzeroidc.a -ldl -lssl -lcrypto - endif - endif -endif - # Disable software updates by default on Linux since that is normally done with package management override DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" @@ -320,27 +257,15 @@ ifeq ($(ZT_OFFICIAL),1) override LDFLAGS+=-Wl,--wrap=memcpy -static-libstdc++ endif -ifeq ($(ZT_CONTROLLER),1) - override CXXFLAGS+=-Wall -Wno-deprecated -std=c++17 -pthread $(INCLUDES) -DNDEBUG $(DEFS) - override LDLIBS+=-Lext/libpqxx-7.7.3/install/ubuntu22.04/$(EXT_ARCH)/lib -lpqxx -lpq ext/hiredis-1.0.2/lib/ubuntu22.04/$(EXT_ARCH)/libhiredis.a ext/redis-plus-plus-1.3.3/install/ubuntu22.04/$(EXT_ARCH)/lib/libredis++.a -lssl -lcrypto - override DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_NO_PEER_METRICS - override INCLUDES+=-I/usr/include/postgresql -Iext/libpqxx-7.7.3/install/ubuntu22.04/$(EXT_ARCH)/include -Iext/hiredis-1.0.2/include/ -Iext/redis-plus-plus-1.3.3/install/ubuntu22.04/$(EXT_ARCH)/include/sw/ - ifeq ($(ZT_DEBUG),1) - override LDLIBS+=rustybits/target/debug/libsmeeclient.a - else - override LDLIBS+=rustybits/target/release/libsmeeclient.a - endif -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=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm - override CXXFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm + 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 ZT_USE_ARM32_NEON_ASM_CRYPTO=0 else - override CFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s - override CXXFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -fexceptions -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s + override CFLAGS+=-march=armv5 -mno-unaligned-access -marm -fexceptions + override CXXFLAGS+=-march=armv5 -mno-unaligned-access -marm -fexceptions ZT_USE_ARM32_NEON_ASM_CRYPTO=0 endif endif @@ -359,25 +284,15 @@ ifeq ($(ZT_USE_ARM32_NEON_ASM_CRYPTO),1) override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o endif -# Position Independence -override CFLAGS+=-fPIC -fPIE -override CXXFLAGS+=-fPIC -fPIE - -# Non-executable stack -override LDFLAGS+=-Wl,-z,noexecstack - .PHONY: all all: one .PHONY: one one: zerotier-one zerotier-idtool zerotier-cli -from_builder: FORCE - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - -zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o +zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS) + $(STRIP) zerotier-one zerotier-idtool: zerotier-one ln -sf zerotier-one zerotier-idtool @@ -385,10 +300,8 @@ zerotier-idtool: zerotier-one zerotier-cli: zerotier-one ln -sf zerotier-one zerotier-cli -$(ONE_OBJS): zeroidc smeeclient - libzerotiercore.a: FORCE - make CFLAGS="-O3 -fstack-protector -fPIC" CXXFLAGS="-O3 -std=c++17 -fstack-protector -fPIC" $(CORE_OBJS) + make CFLAGS="-O3 -fstack-protector -fPIC" CXXFLAGS="-O3 -std=c++11 -fstack-protector -fPIC" $(CORE_OBJS) ar rcs libzerotiercore.a $(CORE_OBJS) ranlib libzerotiercore.a @@ -396,6 +309,7 @@ core: libzerotiercore.a selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LDLIBS) + $(STRIP) zerotier-selftest zerotier-selftest: selftest @@ -405,52 +319,28 @@ 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 docker/zerotier-one rustybits/target + 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 realclean: distclean official: FORCE - make -j`nproc` ZT_OFFICIAL=1 all + make -j4 ZT_OFFICIAL=1 all docker: FORCE - docker build --no-cache -f ext/installfiles/linux/zerotier-containerized/Dockerfile -t zerotier-containerized . - -_buildx: - @echo "docker buildx create" - # docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --privileged --rm tonistiigi/binfmt --install all - @echo docker buildx create --name multiarch --driver docker-container --use - @echo docker buildx inspect --bootstrap + docker build -f ext/installfiles/linux/zerotier-containerized/Dockerfile -t zerotier-containerized . central-controller: FORCE - make -j4 ZT_CONTROLLER=1 one + 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 -central-controller-docker: _buildx FORCE - docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push - @echo Image: registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} +central-controller-docker: central-controller + docker build -t docker.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile . debug: FORCE make ZT_DEBUG=1 one make ZT_DEBUG=1 selftest -ifeq ($(ZT_SSO_SUPPORTED), 1) -ifeq ($(ZT_EMBEDDED),) -zeroidc: FORCE - export PATH=/${HOME}/.cargo/bin:$$PATH; cd rustybits && cargo build $(ZT_CARGO_FLAGS) -p zeroidc -endif -else -zeroidc: -endif - -ifeq ($(ZT_CONTROLLER), 1) -smeeclient: FORCE - export PATH=/${HOME}/.cargo/bin:$$PATH; cd rustybits && cargo build $(ZT_CARGO_FLAGS) -p smeeclient -else -smeeclient: -endif - # 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. @@ -478,7 +368,6 @@ install: FORCE rm -f $(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz cat doc/zerotier-cli.1 | gzip -9 >$(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz cat doc/zerotier-idtool.1 | gzip -9 >$(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - cp ext/installfiles/linux/zerotier-one.te $(DESTDIR)/var/lib/zerotier-one/zerotier-one.te # Uninstall preserves identity.public and identity.secret since the user might # want to save these. These are your ZeroTier address. @@ -500,29 +389,13 @@ uninstall: FORCE # These are just for convenience for building Linux packages -echo_flags: - @echo "=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~" - @echo "echo_flags :: CC=$(CC)" - @echo "echo_flags :: CXX=$(CXX)" - @echo "echo_flags :: CFLAGS=$(CFLAGS)" - @echo "echo_flags :: CXXFLAGS=$(CXXFLAGS)" - @echo "echo_flags :: LDFLAGS=$(LDFLAGS)" - @echo "echo_flags :: RUSTFLAGS=$(RUSTFLAGS)" - @echo "=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~" - -debian: echo_flags - @echo "building deb package" - debuild --no-lintian -I -i -us -uc -nc -b - # debuild --no-lintian -b -uc -us - -# debian: FORCE -# debuild --no-lintian -I -i -us -uc -nc -b +debian: FORCE + debuild -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: - @echo "building rpm package" +redhat: FORCE rpmbuild --target `rpm -q bash --qf "%{arch}"` -ba zerotier-one.spec # This installs the packages needed to build ZT locally on CentOS 7 and @@ -532,37 +405,4 @@ centos-7-setup: FORCE yum install -y centos-release-scl yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ -snap-build-local: FORCE - snapcraft - -snap-install: FORCE - snap install zerotier_`git describe --tags --abbrev=0`_${SNAP_ARCH}.snap --dangerous - -snap-uninstall: FORCE - snap remove zerotier - -snap-build-remote: FORCE - cd pkg && snapcraft remote-build --build-for=amd64,arm64,s390x,ppc64el,armhf,i386 - -snap-upload: ./pkg/*.snap - for file in $^ ; do \ - snapcraft upload --release=beta,edge,candidate $${file} ; \ - done - -synology-pkg: FORCE - cd pkg/synology ; ./build.sh build - -synology-docker: FORCE - cd pkg/synology/dsm7-docker/; ./build.sh build-and-push - -munge_rpm: - @:$(call check_defined, VERSION) - @echo "Updating rpm spec to $(VERSION)" - ci/scripts/munge_rpm_spec.sh zerotier-one.spec $(VERSION) "Adam Ierymenko " "see https://github.com/zerotier/ZeroTierOne for release notes" - -munge_deb: - @:$(call check_defined, VERSION) - @echo "Updating debian/changelog to $(VERSION)" - ci/scripts/munge_debian_changelog.sh debian/changelog $(VERSION) "Adam Ierymenko " "see https://github.com/zerotier/ZeroTierOne for release notes" - FORCE: diff --git a/attic/make-mac.mk b/attic/make-mac.mk new file mode 100644 index 00000000..3eb8a277 --- /dev/null +++ b/attic/make-mac.mk @@ -0,0 +1,155 @@ +CC=clang +CXX=clang++ +INCLUDES= +DEFS= +LIBS= +ARCH_FLAGS= +CODESIGN=echo +PRODUCTSIGN=echo +CODESIGN_APP_CERT= +CODESIGN_INSTALLER_CERT= +NOTARIZE=echo +NOTARIZE_USER_ID=null + +ZT_BUILD_PLATFORM=3 +ZT_BUILD_ARCHITECTURE=2 +ZT_VERSION_MAJOR=$(shell cat version.h | grep -F VERSION_MAJOR | cut -d ' ' -f 3) +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) + +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 + DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER +endif + +# Official releases are signed with our Apple cert and apply software updates by default +ifeq ($(ZT_OFFICIAL_RELEASE),1) + DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"apply\"" + ZT_USE_MINIUPNPC=1 + CODESIGN=codesign + 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 + +# Use fast ASM Salsa20/12 for x64 processors +DEFS+=-DZT_USE_X64_ASM_SALSA2012 +CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o + +# Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources +DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR +ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o + +# Build with address sanitization library for advanced debugging (clang) +ifeq ($(ZT_SANITIZE),1) + DEFS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 +endif +ifeq ($(ZT_DEBUG_TRACE),1) + DEFS+=-DZT_DEBUG_TRACE +endif +# Debug mode -- dump trace output, build binary with -g +ifeq ($(ZT_DEBUG),1) + ZT_TRACE=1 + CFLAGS+=-Wall -g -maes -mpclmul $(INCLUDES) $(DEFS) + STRIP=echo + # The following line enables optimization for the crypto code, since + # C25519 in particular is almost UNUSABLE in heavy testing without it. +node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o node/AES.o: CFLAGS = -Wall -O2 -g -maes -mpclmul $(INCLUDES) $(DEFS) +else + CFLAGS?=-Ofast -fstack-protector-strong + CFLAGS+=$(ARCH_FLAGS) -Wall -flto -fPIE -maes -msse -msse2 -msse3 -mpclmul -mmacosx-version-min=10.9 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS) + STRIP=strip +endif + +ifeq ($(ZT_TRACE),1) + DEFS+=-DZT_TRACE +endif + +ifeq ($(ZT_VAULT_SUPPORT),1) + DEFS+=-DZT_VAULT_SUPPORT=1 + LIBS+=-lcurl +endif + +CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ + +all: one macui + +ext/x64-salsa2012-asm/salsa2012.o: + $(CC) $(CFLAGS) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o + +mac-agent: FORCE + $(CC) -Ofast -o MacEthernetTapAgent osdep/MacEthernetTapAgent.c + $(CODESIGN) -f -s $(CODESIGN_APP_CERT) MacEthernetTapAgent + +one: $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent + $(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) + $(STRIP) zerotier-one + ln -sf zerotier-one zerotier-idtool + ln -sf zerotier-one zerotier-cli + $(CODESIGN) -f -s $(CODESIGN_APP_CERT) zerotier-one + +zerotier-one: one + +central-controller: + make ZT_CONTROLLER=1 one + +zerotier-idtool: one + +zerotier-cli: one + +libzerotiercore.a: $(CORE_OBJS) + ar rcs libzerotiercore.a $(CORE_OBJS) + ranlib libzerotiercore.a + +core: libzerotiercore.a + +macui: FORCE + cd macui && xcodebuild -target "ZeroTier One" -configuration Release + $(CODESIGN) -f -s $(CODESIGN_APP_CERT) "macui/build/Release/ZeroTier One.app" + +#cli: FORCE +# $(CXX) $(CXXFLAGS) -o zerotier cli/zerotier.cpp osdep/OSUtils.cpp node/InetAddress.cpp node/Utils.cpp node/Salsa20.cpp node/Identity.cpp node/SHA512.cpp node/C25519.cpp -lcurl +# $(STRIP) zerotier + +selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o + $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LIBS) + $(STRIP) zerotier-selftest + +zerotier-selftest: selftest + +# Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html +mac-dist-pkg: FORCE + packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" + rm -f "ZeroTier One Signed.pkg" + $(PRODUCTSIGN) --sign $(CODESIGN_INSTALLER_CERT) "ZeroTier One.pkg" "ZeroTier One Signed.pkg" + 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 + make clean + make ZT_OFFICIAL_RELEASE=1 -j 8 one + make ZT_OFFICIAL_RELEASE=1 macui + make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg + +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)_* + +distclean: clean + +realclean: clean + +FORCE: diff --git a/make-netbsd.mk b/attic/make-netbsd.mk similarity index 100% rename from make-netbsd.mk rename to attic/make-netbsd.mk diff --git a/objects.mk b/attic/objects.mk similarity index 72% rename from objects.mk rename to attic/objects.mk index 1d8a6c0a..2bc708d8 100644 --- a/objects.mk +++ b/attic/objects.mk @@ -1,16 +1,12 @@ CORE_OBJS=\ node/AES.o \ - node/AES_aesni.o \ - node/AES_armcrypto.o \ node/C25519.o \ - node/Capability.o \ - node/CertificateOfMembership.o \ - node/CertificateOfOwnership.o \ + node/Credential.o \ + node/ECC384.o \ node/Identity.o \ node/IncomingPacket.o \ node/InetAddress.o \ node/Membership.o \ - node/Metrics.o \ node/Multicaster.o \ node/Network.o \ node/NetworkConfig.o \ @@ -20,17 +16,12 @@ CORE_OBJS=\ node/Path.o \ node/Peer.o \ node/Poly1305.o \ - node/Revocation.o \ node/Salsa20.o \ node/SelfAwareness.o \ node/SHA512.o \ node/Switch.o \ - node/Tag.o \ - node/Topology.o \ node/Trace.o \ - node/Utils.o \ - node/Bond.o \ - node/PacketMultiplexer.o + node/Utils.o ONE_OBJS=\ controller/EmbeddedNetworkController.o \ @@ -39,6 +30,7 @@ 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/attic/one.cpp similarity index 61% rename from one.cpp rename to attic/one.cpp index 2e4e6384..2a3be098 100644 --- a/one.cpp +++ b/attic/one.cpp @@ -1,20 +1,16 @@ /* - * Copyright (c)2020 ZeroTier, Inc. + * 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: 2026-01-01 + * 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. */ /****/ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - #include #include #include @@ -25,16 +21,13 @@ #include "node/Constants.hpp" #ifdef __WINDOWS__ -#include -#include +#include +#include #include #include #include #include #include -#include -#include -#include #include "osdep/WindowsEthernetTap.hpp" #include "windows/ZeroTierOne/ServiceInstaller.h" #include "windows/ZeroTierOne/ServiceBase.h" @@ -52,11 +45,6 @@ #include #include #include -#include -#include -#include -#include -#include #ifndef ZT_NO_CAPABILITIES #include #include @@ -78,25 +66,14 @@ #include "node/Utils.hpp" #include "node/NetworkController.hpp" #include "node/Buffer.hpp" -#include "node/World.hpp" #include "osdep/OSUtils.hpp" #include "osdep/Http.hpp" #include "osdep/Thread.hpp" -#include "node/Bond.hpp" - #include "service/OneService.hpp" -#include - -#ifdef __APPLE__ -#include -#include -#include -#include -#include -#endif +#include "ext/json/json.hpp" #define ZT_PID_PATH "zerotier-one.pid" @@ -105,7 +82,7 @@ using namespace ZeroTier; static OneService *volatile zt1Service = (OneService *)0; #define PROGRAM_NAME "ZeroTier One" -#define COPYRIGHT_NOTICE "Copyright (c) 2020 ZeroTier, Inc." +#define COPYRIGHT_NOTICE "Copyright (c) 2019 ZeroTier, Inc." #define LICENSE_GRANT "Licensed under the ZeroTier BSL 1.1 (see LICENSE.txt)" /****************************************************************************/ @@ -117,10 +94,9 @@ static OneService *volatile zt1Service = (OneService *)0; static void cliPrintHelp(const char *pn,FILE *out) { fprintf(out, - "%s version %d.%d.%d build %d (platform %d arch %d)" ZT_EOL_S, + "%s version %d.%d.%d build %d" ZT_EOL_S, PROGRAM_NAME, - ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION, ZEROTIER_ONE_VERSION_BUILD, - ZT_BUILD_PLATFORM, ZT_BUILD_ARCHITECTURE); + ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION, ZEROTIER_ONE_VERSION_BUILD); fprintf(out, COPYRIGHT_NOTICE ZT_EOL_S LICENSE_GRANT ZT_EOL_S); @@ -137,19 +113,15 @@ 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," 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); - fprintf(out," dump - Debug settings dump for support" 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,ZT_EOL_S"Available settings:" ZT_EOL_S); 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); } @@ -171,7 +143,7 @@ static int cli(int argc,char **argv) #endif { unsigned int port = 0; - std::string homeDir,command,arg1,arg2,arg3,arg4,authToken; + std::string homeDir,command,arg1,arg2,authToken; std::string ip("127.0.0.1"); bool json = false; for(int i=1;i " ZT_EOL_S); + printf("200 peers\n " ZT_EOL_S); if (j.is_array()) { for(unsigned long k=0;k */ - if (arg1.empty()) { - printf("(bond) command is missing required arguments" ZT_EOL_S); - return 2; - } - /* zerotier-cli bond list */ - if (arg1 == "list") { - const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody); - if (scode == 0) { - printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str()); - return 1; - } - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - if (scode == 200) { - if (json) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - } else { - bool bFoundBond = false; - printf(" " ZT_EOL_S); - if (j.is_array()) { - for(unsigned long k=0;k= ZT_BOND_POLICY_NONE && bondingPolicyCode <= ZT_BOND_POLICY_BALANCE_AWARE) { - policyStr = Bond::getPolicyStrByCode(bondingPolicyCode); - } - printf("%10s %32s %d/%d" ZT_EOL_S, - OSUtils::jsonString(p ["address"],"-").c_str(), - policyStr.c_str(), - numAliveLinks, - numTotalLinks); - } - } - } - if (!bFoundBond) { - printf(" NONE\t\t\t\tNONE\t NONE NONE" ZT_EOL_S); - } - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } - else if (arg1 == "setmtu") { /* zerotier-cli bond setmtu */ - requestHeaders["Content-Type"] = "application/json"; - requestHeaders["Content-Length"] = "2"; - if (argc == 8) { - arg2 = argv[5]; - arg3 = argv[6]; - arg4 = argv[7]; - } - unsigned int scode = Http::POST( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/bond/") + arg1 + "/" + arg2 + "/" + arg3 + "/" + arg4).c_str(), - requestHeaders, - "{}", - 2, - responseHeaders, - responseBody); - if (scode == 200) { - printf("200 setmtu OK" ZT_EOL_S); - return 0; - } else { - printf("%d Failed to set MTU: %s" ZT_EOL_S, scode, responseBody.c_str()); - return 1; - } - return 0; - } - else if (arg1.length() == 10) { - if (arg2 == "rotate") { /* zerotier-cli bond rotate */ - requestHeaders["Content-Type"] = "application/json"; - requestHeaders["Content-Length"] = "2"; - unsigned int scode = Http::POST( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/bond/") + arg2 + "/" + arg1).c_str(), - requestHeaders, - "{}", - 2, - responseHeaders, - responseBody); - if (scode == 200) { - if (json) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - } else { - printf("200 rotate OK" ZT_EOL_S); - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - return 0; - } - if (arg2 == "show") { - //fprintf(stderr, "zerotier-cli bond show\n"); - const unsigned int scode = Http::GET( - 1024 * 1024 * 16,60000, - (const struct sockaddr *)&addr,(std::string("/bond/") + arg2 + "/" + arg1).c_str(), - requestHeaders, - responseHeaders, - responseBody); - if (scode == 0) { - printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str()); - return 1; - } - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - if (scode == 200) { - if (json) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - } else { - int numAliveLinks = OSUtils::jsonInt(j["numAliveLinks"],0); - int numTotalLinks = OSUtils::jsonInt(j["numTotalLinks"],0); - printf("Peer : %s\n", arg1.c_str()); - printf("Bond : %s\n", OSUtils::jsonString(j["bondingPolicyStr"],"-").c_str()); - printf("Link Select Method : %d\n", (int)OSUtils::jsonInt(j["linkSelectMethod"],0)); - printf("Links : %d/%d\n", numAliveLinks, numTotalLinks); - printf("Failover Interval (ms) : %d\n", (int)OSUtils::jsonInt(j["failoverInterval"],0)); - printf("Up Delay (ms) : %d\n", (int)OSUtils::jsonInt(j["upDelay"],0)); - printf("Down Delay (ms) : %d\n", (int)OSUtils::jsonInt(j["downDelay"],0)); - printf("Packets Per Link : %d\n", (int)OSUtils::jsonInt(j["packetsPerLink"],0)); - nlohmann::json &p = j["paths"]; - if (p.is_array()) { - printf("\nidx" - " interface" - " " - "path socket local port\n"); - for(int i=0; i<120; i++) { printf("-"); } - printf("\n"); - for (int i=0; i " ZT_EOL_S); - if (j.is_array()) { - for(unsigned long k=0;k= ZT_BOND_POLICY_NONE && bondingPolicyCode <= ZT_BOND_POLICY_BALANCE_AWARE) { - policyStr = Bond::getPolicyStrByCode(bondingPolicyCode); - } - printf("%10s %32s %d/%d" ZT_EOL_S, - OSUtils::jsonString(p["address"],"-").c_str(), - policyStr.c_str(), - numAliveLinks, - numTotalLinks); - } - } - } - if (!bFoundBond) { - printf(" NONE\t\t\t\tNONE\t NONE NONE" ZT_EOL_S); - } } return 0; } else { @@ -805,26 +502,14 @@ static int cli(int argc,char **argv) } } if (aa.length() == 0) aa = "-"; - const std::string status = OSUtils::jsonString(n["status"],"-"); printf("200 listnetworks %s %s %s %s %s %s %s" ZT_EOL_S, OSUtils::jsonString(n["nwid"],"-").c_str(), OSUtils::jsonString(n["name"],"-").c_str(), OSUtils::jsonString(n["mac"],"-").c_str(), - status.c_str(), + OSUtils::jsonString(n["status"],"-").c_str(), OSUtils::jsonString(n["type"],"-").c_str(), OSUtils::jsonString(n["portDeviceName"],"-").c_str(), aa.c_str()); - if (OSUtils::jsonBool(n["ssoEnabled"], false)) { - uint64_t authenticationExpiryTime = n["authenticationExpiryTime"]; - if (status == "AUTHENTICATION_REQUIRED") { - printf(" AUTH EXPIRED, URL: %s" ZT_EOL_S, OSUtils::jsonString(n["authenticationURL"], "(null)").c_str()); - } else if (status == "OK") { - int64_t expiresIn = ((int64_t)authenticationExpiryTime - OSUtils::now()) / 1000LL; - if (expiresIn >= 0) { - printf(" AUTH OK, expires in: %lld seconds" ZT_EOL_S, expiresIn); - } - } - } } } } @@ -886,80 +571,6 @@ static int cli(int argc,char **argv) printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); return 1; } - } else if (command == "listmoons") { - const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/moon",requestHeaders,responseHeaders,responseBody); - - if (scode == 0) { - printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str()); - return 1; - } - - nlohmann::json j; - try { - j = OSUtils::jsonParse(responseBody); - } catch (std::exception &exc) { - printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what()); - return 1; - } catch ( ... ) { - printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str()); - return 1; - } - - if (scode == 200) { - printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } else if (command == "orbit") { - const uint64_t worldId = Utils::hexStrToU64(arg1.c_str()); - const uint64_t seed = Utils::hexStrToU64(arg2.c_str()); - if ((worldId)&&(seed)) { - char jsons[1024]; - OSUtils::ztsnprintf(jsons,sizeof(jsons),"{\"seed\":\"%s\"}",arg2.c_str()); - char cl[128]; - OSUtils::ztsnprintf(cl,sizeof(cl),"%u",(unsigned int)strlen(jsons)); - requestHeaders["Content-Type"] = "application/json"; - requestHeaders["Content-Length"] = cl; - unsigned int scode = Http::POST( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/moon/") + arg1).c_str(), - requestHeaders, - jsons, - (unsigned long)strlen(jsons), - responseHeaders, - responseBody); - if (scode == 200) { - printf("200 orbit OK" ZT_EOL_S); - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } - } - } else if (command == "deorbit") { - unsigned int scode = Http::DEL( - 1024 * 1024 * 16, - 60000, - (const struct sockaddr *)&addr, - (std::string("/moon/") + arg1).c_str(), - requestHeaders, - responseHeaders, - responseBody); - if (scode == 200) { - if (json) { - printf("%s",cliFixJsonCRs(responseBody).c_str()); - } else { - printf("200 deorbit OK" ZT_EOL_S); - } - return 0; - } else { - printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); - return 1; - } } else if (command == "set") { if (arg1.length() != 16) { fprintf(stderr,"invalid format: must be a 16-digit (network) ID\n"); @@ -971,7 +582,7 @@ static int cli(int argc,char **argv) } std::size_t eqidx = arg2.find('='); if (eqidx != std::string::npos) { - if ((arg2.substr(0,eqidx) == "allowManaged")||(arg2.substr(0,eqidx) == "allowGlobal")||(arg2.substr(0,eqidx) == "allowDefault")||(arg2.substr(0,eqidx) == "allowDNS")) { + if ((arg2.substr(0,eqidx) == "allowManaged")||(arg2.substr(0,eqidx) == "allowGlobal")||(arg2.substr(0,eqidx) == "allowDefault")) { char jsons[1024]; OSUtils::ztsnprintf(jsons,sizeof(jsons),"{\"%s\":%s}", arg2.substr(0,eqidx).c_str(), @@ -1049,7 +660,7 @@ static int cli(int argc,char **argv) int addressCountOfType = 0; for (int k = 0; k().find('.') != std::string::npos) + if ((arg2 == "ip4" && addr.get().find(".") != std::string::npos) || ((arg2.find("ip6") == 0) && addr.get().find(":") != std::string::npos) || (arg2 == "ip") ) { @@ -1064,19 +675,19 @@ static int cli(int argc,char **argv) if (arg2.find("ip6p") == 0) { if (arg2 == "ip6plane") { if (addr.get().find("fc") == 0) { - aa.append(addr.get().substr(0,addr.get().find('/'))); + aa.append(addr.get().substr(0,addr.get().find("/"))); if (k < addressCountOfType-1) aa.append("\n"); } } if (arg2 == "ip6prefix") { if (addr.get().find("fc") == 0) { - aa.append(addr.get().substr(0,addr.get().find('/')).substr(0,24)); + aa.append(addr.get().substr(0,addr.get().find("/")).substr(0,24)); if (k < addressCountOfType-1) aa.append("\n"); } } } else { - aa.append(addr.get().substr(0,addr.get().find('/'))); + aa.append(addr.get().substr(0,addr.get().find("/"))); if (k < addressCountOfType-1) aa.append("\n"); } } @@ -1095,315 +706,6 @@ static int cli(int argc,char **argv) printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); return 1; } - } else if (command == "dump") { - std::stringstream dump; - dump << "platform: "; -#ifdef __APPLE__ - dump << "macOS" << ZT_EOL_S; -#elif defined(_WIN32) - dump << "Windows" << ZT_EOL_S; -#elif defined(__LINUX__) - dump << "Linux" << ZT_EOL_S; -#else - dump << "other unix based OS" << ZT_EOL_S; -#endif - dump << "zerotier version: " << ZEROTIER_ONE_VERSION_MAJOR << "." - << ZEROTIER_ONE_VERSION_MINOR << "." << ZEROTIER_ONE_VERSION_REVISION << ZT_EOL_S << ZT_EOL_S; - - // grab status - dump << "status" << ZT_EOL_S << "------" << ZT_EOL_S; - unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/status",requestHeaders,responseHeaders,responseBody); - if (scode != 200) { - printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str()); - return 1; - } - dump << responseBody << ZT_EOL_S; - - responseHeaders.clear(); - responseBody = ""; - - // grab network list - dump << ZT_EOL_S << "networks" << ZT_EOL_S << "--------" << ZT_EOL_S; - scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody); - if (scode != 200) { - printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str()); - return 1; - } - dump << responseBody << ZT_EOL_S; - - responseHeaders.clear(); - responseBody = ""; - - // list peers - dump << ZT_EOL_S << "peers" << ZT_EOL_S << "-----" << ZT_EOL_S; - scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody); - if (scode != 200) { - printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str()); - return 1; - } - dump << responseBody << ZT_EOL_S; - - // Bonds don't need to be queried separately since their data originates from "/peer" responses anyway - - responseHeaders.clear(); - responseBody = ""; - - dump << ZT_EOL_S << "local.conf" << ZT_EOL_S << "----------" << ZT_EOL_S; - std::string localConf; - OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "local.conf").c_str(), localConf); - if (localConf.empty()) { - dump << "None Present" << ZT_EOL_S; - } - else { - dump << localConf << ZT_EOL_S; - } - - dump << ZT_EOL_S << "Network Interfaces" << ZT_EOL_S << "------------------" << ZT_EOL_S << ZT_EOL_S; -#ifdef __APPLE__ - CFArrayRef interfaces = SCNetworkInterfaceCopyAll(); - CFIndex size = CFArrayGetCount(interfaces); - for(CFIndex i = 0; i < size; ++i) { - SCNetworkInterfaceRef iface = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(interfaces, i); - - dump << "Interface " << i << ZT_EOL_S << "-----------" << ZT_EOL_S; - CFStringRef tmp = SCNetworkInterfaceGetBSDName(iface); - char stringBuffer[512] = {}; - CFStringGetCString(tmp,stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8); - dump << "Name: " << stringBuffer << ZT_EOL_S; - std::string ifName(stringBuffer); - int mtuCur, mtuMin, mtuMax; - SCNetworkInterfaceCopyMTU(iface, &mtuCur, &mtuMin, &mtuMax); - dump << "MTU: " << mtuCur << ZT_EOL_S; - tmp = SCNetworkInterfaceGetHardwareAddressString(iface); - CFStringGetCString(tmp, stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8); - dump << "MAC: " << stringBuffer << ZT_EOL_S; - tmp = SCNetworkInterfaceGetInterfaceType(iface); - CFStringGetCString(tmp, stringBuffer, sizeof(stringBuffer), kCFStringEncodingUTF8); - dump << "Type: " << stringBuffer << ZT_EOL_S; - dump << "Addresses:" << ZT_EOL_S; - - struct ifaddrs *ifap, *ifa; - void *addr; - getifaddrs(&ifap); - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (strcmp(ifName.c_str(), ifa->ifa_name) == 0) { - if (ifa->ifa_addr->sa_family == AF_INET) { - struct sockaddr_in *ipv4 = (struct sockaddr_in*)ifa->ifa_addr; - addr = &ipv4->sin_addr; - } else if (ifa->ifa_addr->sa_family == AF_INET6) { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)ifa->ifa_addr; - addr = &ipv6->sin6_addr; - } else { - continue; - } - inet_ntop(ifa->ifa_addr->sa_family, addr, stringBuffer, sizeof(stringBuffer)); - dump << stringBuffer << ZT_EOL_S; - } - } - - dump << ZT_EOL_S; - } - - - FSRef fsref; - UInt8 path[PATH_MAX]; - if (FSFindFolder(kUserDomain, kDesktopFolderType, kDontCreateFolder, &fsref) == noErr && - FSRefMakePath(&fsref, path, sizeof(path)) == noErr) { - - } else if (getenv("SUDO_USER")) { - sprintf((char*)path, "/Users/%s/Desktop", getenv("SUDO_USER")); - } else { - fprintf(stdout, "%s", dump.str().c_str()); - return 0; - } - - sprintf((char*)path, "%s%szerotier_dump.txt", (char*)path, ZT_PATH_SEPARATOR_S); - - fprintf(stdout, "Writing dump to: %s\n", path); - int fd = open((char*)path, O_CREAT|O_RDWR,0664); - if (fd == -1) { - fprintf(stderr, "Error creating file.\n"); - return 1; - } - write(fd, dump.str().c_str(), dump.str().size()); - close(fd); -#elif defined(_WIN32) - ULONG buffLen = 16384; - PIP_ADAPTER_ADDRESSES addresses; - - ULONG ret = 0; - do { - addresses = (PIP_ADAPTER_ADDRESSES)malloc(buffLen); - - ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &buffLen); - if (ret == ERROR_BUFFER_OVERFLOW) { - free(addresses); - addresses = NULL; - } - else { - break; - } - } while (ret == ERROR_BUFFER_OVERFLOW); - - int i = 0; - if (ret == NO_ERROR) { - PIP_ADAPTER_ADDRESSES curAddr = addresses; - while (curAddr) { - dump << "Interface " << i << ZT_EOL_S << "-----------" << ZT_EOL_S; - dump << "Name: " << curAddr->AdapterName << ZT_EOL_S; - dump << "MTU: " << curAddr->Mtu << ZT_EOL_S; - dump << "MAC: "; - char macBuffer[64] = {}; - sprintf(macBuffer, "%02x:%02x:%02x:%02x:%02x:%02x", - curAddr->PhysicalAddress[0], - curAddr->PhysicalAddress[1], - curAddr->PhysicalAddress[2], - curAddr->PhysicalAddress[3], - curAddr->PhysicalAddress[4], - curAddr->PhysicalAddress[5]); - dump << macBuffer << ZT_EOL_S; - dump << "Type: " << curAddr->IfType << ZT_EOL_S; - dump << "Addresses:" << ZT_EOL_S; - PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; - pUnicast = curAddr->FirstUnicastAddress; - if (pUnicast) { - for (int j = 0; pUnicast != NULL; ++j) { - char buf[128] = {}; - DWORD bufLen = 128; - LPSOCKADDR a = pUnicast->Address.lpSockaddr; - WSAAddressToStringA( - pUnicast->Address.lpSockaddr, - pUnicast->Address.iSockaddrLength, - NULL, - buf, - &bufLen - ); - dump << buf << ZT_EOL_S; - pUnicast = pUnicast->Next; - } - } - - curAddr = curAddr->Next; - ++i; - } - } - if (addresses) { - free(addresses); - addresses = NULL; - } - - char path[MAX_PATH + 1] = {}; - if (SHGetFolderPathA(NULL, CSIDL_DESKTOP, NULL, 0, path) == S_OK) { - sprintf(path, "%s%szerotier_dump.txt", path, ZT_PATH_SEPARATOR_S); - fprintf(stdout, "Writing dump to: %s\n", path); - HANDLE file = CreateFileA( - path, - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL - ); - if (file == INVALID_HANDLE_VALUE) { - fprintf(stdout, "%s", dump.str().c_str()); - return 0; - } - - BOOL err = WriteFile( - file, - dump.str().c_str(), - dump.str().size(), - NULL, - NULL - ); - if (err = FALSE) { - fprintf(stderr, "Error writing file"); - return 1; - } - CloseHandle(file); - } - else { - fprintf(stdout, "%s", dump.str().c_str()); - } -#elif defined(__LINUX__) - struct ifreq ifr; - struct ifconf ifc; - char buf[1024]; - char stringBuffer[128]; - - int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; - ioctl(sock, SIOCGIFCONF, &ifc); - - struct ifreq *it = ifc.ifc_req; - const struct ifreq * const end = it + (ifc.ifc_len / sizeof(struct ifreq)); - int count = 0; - for(; it != end; ++it) { - strcpy(ifr.ifr_name, it->ifr_name); - if(ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { - if (!(ifr.ifr_flags & IFF_LOOPBACK)) { // skip loopback - dump << "Interface " << count++ << ZT_EOL_S << "-----------" << ZT_EOL_S; - dump << "Name: " << ifr.ifr_name << ZT_EOL_S; - if (ioctl(sock, SIOCGIFMTU, &ifr) == 0) { - dump << "MTU: " << ifr.ifr_mtu << ZT_EOL_S; - } - if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { - unsigned char mac_addr[6]; - memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, 6); - char macStr[18]; - sprintf(macStr, "%02x:%02x:%02x:%02x:%02x:%02x", - mac_addr[0], - mac_addr[1], - mac_addr[2], - mac_addr[3], - mac_addr[4], - mac_addr[5]); - dump << "MAC: " << macStr << ZT_EOL_S; - } - - dump << "Addresses: " << ZT_EOL_S; - struct ifaddrs *ifap, *ifa; - void *addr; - getifaddrs(&ifap); - for(ifa = ifap; ifa; ifa = ifa->ifa_next) { - if(strcmp(ifr.ifr_name, ifa->ifa_name) == 0 && ifa->ifa_addr != NULL) { - if(ifa->ifa_addr->sa_family == AF_INET) { - struct sockaddr_in *ipv4 = (struct sockaddr_in*)ifa->ifa_addr; - addr = &ipv4->sin_addr; - } else if (ifa->ifa_addr->sa_family == AF_INET6) { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)ifa->ifa_addr; - addr = &ipv6->sin6_addr; - } else { - continue; - } - inet_ntop(ifa->ifa_addr->sa_family, addr, stringBuffer, sizeof(stringBuffer)); - dump << stringBuffer << ZT_EOL_S; - } - } - } - } - } - close(sock); - char cwd[16384]; - getcwd(cwd, sizeof(cwd)); - sprintf(cwd, "%s%szerotier_dump.txt", cwd, ZT_PATH_SEPARATOR_S); - fprintf(stdout, "Writing dump to: %s\n", cwd); - int fd = open(cwd, O_CREAT|O_RDWR,0664); - if (fd == -1) { - fprintf(stderr, "Error creating file.\n"); - return 1; - } - write(fd, dump.str().c_str(), dump.str().size()); - close(fd); -#else - fprintf(stderr, "%s", dump.str().c_str()); -#endif - - // fprintf(stderr, "%s\n", dump.str().c_str()); - } else { cliPrintHelp(argv[0],stderr); return 0; @@ -1431,8 +733,6 @@ static void idtoolPrintHelp(FILE *out,const char *pn) fprintf(out," getpublic " ZT_EOL_S); fprintf(out," sign " ZT_EOL_S); fprintf(out," verify " ZT_EOL_S); - fprintf(out," initmoon " ZT_EOL_S); - fprintf(out," genmoon " ZT_EOL_S); } static Identity getIdFromArg(char *arg) @@ -1474,7 +774,7 @@ static int idtool(int argc,char **argv) Identity id; for(;;) { - id.generate(); + id.generate(Identity::C25519); if ((id.address().toInt() >> (40 - vanityBits)) == vanity) { if (vanityBits > 0) { fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt()); @@ -1552,9 +852,10 @@ static int idtool(int argc,char **argv) fprintf(stderr,"%s is not readable" ZT_EOL_S,argv[3]); return 1; } - C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length()); - char hexbuf[1024]; - printf("%s",Utils::hex(signature.data,ZT_C25519_SIGNATURE_LEN,hexbuf)); + uint8_t signature[ZT_SIGNATURE_BUFFER_SIZE]; + const unsigned int siglen = id.sign(inf.data(),(unsigned int)inf.length(),signature,sizeof(signature)); + char hexbuf[256]; + printf("%s",Utils::hex(signature,siglen,hexbuf)); } else if (!strcmp(argv[1],"verify")) { if (argc < 5) { idtoolPrintHelp(stdout,argv[0]); @@ -1592,94 +893,6 @@ static int idtool(int argc,char **argv) return 1; } } - } else if (!strcmp(argv[1],"initmoon")) { - if (argc < 3) { - idtoolPrintHelp(stdout,argv[0]); - } else { - const Identity id = getIdFromArg(argv[2]); - if (!id) { - fprintf(stderr,"%s is not a valid identity" ZT_EOL_S,argv[2]); - return 1; - } - - C25519::Pair kp(C25519::generate()); - - char idtmp[4096]; - nlohmann::json mj; - mj["objtype"] = "world"; - mj["worldType"] = "moon"; - mj["updatesMustBeSignedBy"] = mj["signingKey"] = Utils::hex(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,idtmp); - mj["signingKey_SECRET"] = Utils::hex(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN,idtmp); - mj["id"] = id.address().toString(idtmp); - nlohmann::json seedj; - seedj["identity"] = id.toString(false,idtmp); - seedj["stableEndpoints"] = nlohmann::json::array(); - (mj["roots"] = nlohmann::json::array()).push_back(seedj); - std::string mjd(OSUtils::jsonDump(mj)); - - printf("%s" ZT_EOL_S,mjd.c_str()); - } - } else if (!strcmp(argv[1],"genmoon")) { - if (argc < 3) { - idtoolPrintHelp(stdout,argv[0]); - } else { - std::string buf; - if (!OSUtils::readFile(argv[2],buf)) { - fprintf(stderr,"cannot read %s" ZT_EOL_S,argv[2]); - return 1; - } - nlohmann::json mj(OSUtils::jsonParse(buf)); - - const uint64_t id = Utils::hexStrToU64(OSUtils::jsonString(mj["id"],"0").c_str()); - if (!id) { - fprintf(stderr,"ID in %s is invalid" ZT_EOL_S,argv[2]); - return 1; - } - - World::Type t; - if (mj["worldType"] == "moon") { - t = World::TYPE_MOON; - } else if (mj["worldType"] == "planet") { - t = World::TYPE_PLANET; - } else { - fprintf(stderr,"invalid worldType" ZT_EOL_S); - return 1; - } - - C25519::Pair signingKey; - C25519::Public updatesMustBeSignedBy; - Utils::unhex(OSUtils::jsonString(mj["signingKey"],"").c_str(),signingKey.pub.data,ZT_C25519_PUBLIC_KEY_LEN); - Utils::unhex(OSUtils::jsonString(mj["signingKey_SECRET"],"").c_str(),signingKey.priv.data,ZT_C25519_PRIVATE_KEY_LEN); - Utils::unhex(OSUtils::jsonString(mj["updatesMustBeSignedBy"],"").c_str(),updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); - - std::vector roots; - nlohmann::json &rootsj = mj["roots"]; - if (rootsj.is_array()) { - for(unsigned long i=0;i<(unsigned long)rootsj.size();++i) { - nlohmann::json &r = rootsj[i]; - if (r.is_object()) { - roots.push_back(World::Root()); - roots.back().identity = Identity(OSUtils::jsonString(r["identity"],"").c_str()); - nlohmann::json &stableEndpointsj = r["stableEndpoints"]; - if (stableEndpointsj.is_array()) { - for(unsigned long k=0;k<(unsigned long)stableEndpointsj.size();++k) - roots.back().stableEndpoints.push_back(InetAddress(OSUtils::jsonString(stableEndpointsj[k],"").c_str())); - std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end()); - } - } - } - } - std::sort(roots.begin(),roots.end()); - - const int64_t now = OSUtils::now(); - World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey)); - Buffer wbuf; - w.serialize(wbuf); - char fn[128]; - OSUtils::ztsnprintf(fn,sizeof(fn),"%.16llx.moon",w.id()); - OSUtils::writeFile(fn,wbuf.data(),wbuf.size()); - printf("wrote %s (signed world with timestamp %llu)" ZT_EOL_S,fn,(unsigned long long)now); - } } else { idtoolPrintHelp(stdout,argv[0]); return 1; @@ -1696,13 +909,8 @@ static int idtool(int argc,char **argv) static void _sighandlerHup(int sig) { } -static void _sighandlerReallyQuit(int sig) -{ - exit(0); -} static void _sighandlerQuit(int sig) { - alarm(5); // force exit after 5s OneService *s = zt1Service; if (s) s->terminate(); @@ -1872,7 +1080,6 @@ static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType) return FALSE; } -// TODO: revisit this with https://support.microsoft.com/en-us/help/947709/how-to-use-the-netsh-advfirewall-firewall-context-instead-of-the-netsh static void _winPokeAHole() { char myPath[MAX_PATH]; @@ -2088,23 +1295,13 @@ int __cdecl _tmain(int argc, _TCHAR* argv[]) int main(int argc,char **argv) #endif { -#if defined(__LINUX__) && ( (!defined(__GLIBC__)) || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 18)) ) - // This corrects for systems with abnormally small defaults (musl) and also - // shrinks the stack on systems with large defaults to save a bit of memory. - pthread_attr_t tattr; - pthread_attr_init(&tattr); - pthread_attr_setstacksize(&tattr,1048576); - pthread_setattr_default_np(&tattr); - pthread_attr_destroy(&tattr); -#endif - #ifdef __UNIX_LIKE__ signal(SIGHUP,&_sighandlerHup); signal(SIGPIPE,SIG_IGN); signal(SIGIO,SIG_IGN); signal(SIGUSR1,SIG_IGN); signal(SIGUSR2,SIG_IGN); - signal(SIGALRM,&_sighandlerReallyQuit); + signal(SIGALRM,SIG_IGN); signal(SIGINT,&_sighandlerQuit); signal(SIGTERM,&_sighandlerQuit); signal(SIGQUIT,&_sighandlerQuit); @@ -2257,32 +1454,11 @@ int main(int argc,char **argv) ptmp.append(*pi); if ((*pi != ".")&&(*pi != "..")) { if (!OSUtils::mkdir(ptmp)) - throw std::runtime_error("home path does not exist, and could not create. Please verify local system permissions."); + throw std::runtime_error("home path does not exist, and could not create"); } } } - // Check and fix permissions on critical files at startup - try { - char p[4096]; - OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "identity.secret", homeDir.c_str()); - if (OSUtils::fileExists(p)) { - OSUtils::lockDownFile(p, false); - } - } - catch (...) { - } - - try { - char p[4096]; - OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "authtoken.secret", homeDir.c_str()); - if (OSUtils::fileExists(p)) { - OSUtils::lockDownFile(p, false); - } - } - catch (...) { - } - // This can be removed once the new controller code has been around for many versions if (OSUtils::fileExists((homeDir + ZT_PATH_SEPARATOR_S + "controller.db").c_str(),true)) { fprintf(stderr,"%s: FATAL: an old controller.db exists in %s -- see instructions in controller/README.md for how to migrate!" ZT_EOL_S,argv[0],homeDir.c_str()); diff --git a/rule-compiler/README.md b/attic/rule-compiler/README.md similarity index 100% rename from rule-compiler/README.md rename to attic/rule-compiler/README.md diff --git a/rule-compiler/cli.js b/attic/rule-compiler/cli.js similarity index 100% rename from rule-compiler/cli.js rename to attic/rule-compiler/cli.js diff --git a/rule-compiler/examples/capabilities-and-tags.ztrules b/attic/rule-compiler/examples/capabilities-and-tags.ztrules similarity index 100% rename from rule-compiler/examples/capabilities-and-tags.ztrules rename to attic/rule-compiler/examples/capabilities-and-tags.ztrules diff --git a/rule-compiler/package.json b/attic/rule-compiler/package.json similarity index 100% rename from rule-compiler/package.json rename to attic/rule-compiler/package.json diff --git a/rule-compiler/rule-compiler.js b/attic/rule-compiler/rule-compiler.js similarity index 69% rename from rule-compiler/rule-compiler.js rename to attic/rule-compiler/rule-compiler.js index 81bd5e06..f9b3aafa 100644 --- a/rule-compiler/rule-compiler.js +++ b/attic/rule-compiler/rule-compiler.js @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -208,12 +208,13 @@ const MATCH_ARG_COUNTS = { const INTL_ALPHANUM_REGEX = new RegExp('[0-9A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'); // Checks whether something is a valid capability, tag, or macro name -function _isValidName(n) { - if ((typeof n !== 'string') || (n.length === 0)) return false; +function _isValidName(n) +{ + if ((typeof n !== 'string')||(n.length === 0)) return false; if ("0123456789".indexOf(n.charAt(0)) >= 0) return false; - for (let i = 0; i < n.length; ++i) { + for(let i=0;i 2) && (n.substr(0, 2) === '0x')) - n = parseInt(n.substr(2), 16); - else n = parseInt(n, 10); - return (((typeof n === 'number') && (n !== null) && (!isNaN(n))) ? n : -1); + if ((n.length > 2)&&(n.substr(0,2) === '0x')) + n = parseInt(n.substr(2),16); + else n = parseInt(n,10); + return (((typeof n === 'number')&&(n !== null)&&(!isNaN(n))) ? n : -1); } catch (e) { return -1; } } -function _cleanMac(m) { +function _cleanMac(m) +{ m = m.toLowerCase(); var m2 = ''; let charcount = 0; - for (let i = 0; ((i < m.length) && (m2.length < 17)); ++i) { + for(let i=0;((i= 0) { m2 += c; charcount++; - if ((m2.length > 0) && (m2.length !== 17) && (charcount >= 2)) { + if ((m2.length > 0)&&(m2.length !== 17)&&(charcount >= 2) ) { m2 += ':'; - charcount = 0; + charcount=0; } } } return m2; } -function _cleanHex(m) { +function _cleanHex(m) +{ m = m.toLowerCase(); var m2 = ''; - for (let i = 0; i < m.length; ++i) { + for(let i=0;i= 0) m2 += c; @@ -265,12 +269,13 @@ function _cleanHex(m) { return m2; } -function _renderMatches(mtree, rules, macros, caps, tags, params) { +function _renderMatches(mtree,rules,macros,caps,tags,params) +{ let not = false; let or = false; - for (let k = 0; k < mtree.length; ++k) { + for(let k=0;k= mtree.length) - return [mtree[k - 1][1], mtree[k - 1][2], 'Missing argument(s) to match.']; + return [ mtree[k - 1][1],mtree[k - 1][2],'Missing argument(s) to match.' ]; let arg = mtree[k][0]; - if ((typeof arg !== 'string') || (arg in RESERVED_WORDS) || (arg.length === 0)) - return [mtree[k - 1][1], mtree[k - 1][2], 'Missing argument(s) to match (invalid argument or argument is reserved word).']; + if ((typeof arg !== 'string')||(arg in RESERVED_WORDS)||(arg.length === 0)) + return [ mtree[k - 1][1],mtree[k - 1][2],'Missing argument(s) to match (invalid argument or argument is reserved word).' ]; if (arg.charAt(0) === '$') { let tmp = params[arg]; if (typeof tmp === 'undefined') - return [mtree[k][1], mtree[k][2], 'Undefined variable name.']; - args.push([tmp, mtree[k][1], mtree[k][2]]); + return [ mtree[k][1],mtree[k][2],'Undefined variable name.' ]; + args.push([ tmp,mtree[k][1],mtree[k][2] ]); } else { args.push(mtree[k]); } } - switch (match) { + switch(match) { case 'ztsrc': case 'ztdest': { let zt = _cleanHex(args[0][0]); if (zt.length !== 10) - return [args[0][1], args[0][2], 'Invalid ZeroTier address.']; + return [ args[0][1],args[0][2],'Invalid ZeroTier address.' ]; rules.push({ 'type': KEYWORD_TO_API_MAP[match], 'not': not, 'or': or, 'zt': zt }); - } break; + } break; case 'vlan': case 'vlanpcp': @@ -323,14 +328,14 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { } if (typeof num !== 'number') num = _parseNum(args[0][0]); - if ((typeof num !== 'number') || (num < 0) || (num > 0xffffffff) || (num === null)) - return [args[0][1], args[0][2], 'Invalid numeric value.']; + if ((typeof num !== 'number')||(num < 0)||(num > 0xffffffff)||(num === null)) + return [ args[0][1],args[0][2],'Invalid numeric value.' ]; let r = { 'type': KEYWORD_TO_API_MAP[match], 'not': not, 'or': or }; - switch (match) { + switch(match) { case 'vlan': r['vlanId'] = num; break; case 'vlanpcp': r['vlanPcp'] = num; break; case 'vlandei': r['vlanDei'] = num; break; @@ -338,10 +343,10 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { case 'ipprotocol': r['ipProtocol'] = num; break; } rules.push(r); - } break; + } break; case 'random': { - let num = parseFloat(args[0][0]) || 0.0; + let num = parseFloat(args[0][0])||0.0; if (num < 0.0) num = 0.0; if (num > 1.0) num = 1.0; rules.push({ @@ -350,28 +355,28 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'or': or, 'probability': Math.floor(4294967295 * num) }); - } break; + } break; case 'macsrc': case 'macdest': { let mac = _cleanMac(args[0][0]); if (mac.length !== 17) - return [args[0][1], args[0][2], 'Invalid MAC address.']; + return [ args[0][1],args[0][2],'Invalid MAC address.' ]; rules.push({ 'type': KEYWORD_TO_API_MAP[match], 'not': not, 'or': or, 'mac': mac }); - } break; + } break; case 'ipsrc': case 'ipdest': { let ip = args[0][0]; let slashIdx = ip.indexOf('/'); if (slashIdx <= 0) - return [args[0][1], args[0][2], 'Missing /bits netmask length designation in IP.']; - let ipOnly = ip.substr(0, slashIdx); + return [ args[0][1],args[0][2],'Missing /bits netmask length designation in IP.' ]; + let ipOnly = ip.substr(0,slashIdx); if (IPV6_REGEX.test(ipOnly)) { rules.push({ 'type': ((match === 'ipsrc') ? 'MATCH_IPV6_SOURCE' : 'MATCH_IPV6_DEST'), @@ -387,17 +392,17 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'ip': ip }); } else { - return [args[0][1], args[0][2], 'Invalid IP address (not valid IPv4 or IPv6).']; + return [ args[0][1],args[0][2],'Invalid IP address (not valid IPv4 or IPv6).' ]; } - } break; + } break; case 'icmp': { let icmpType = _parseNum(args[0][0]); - if ((icmpType < 0) || (icmpType > 0xff)) - return [args[0][1], args[0][2], 'Missing or invalid ICMP type.']; + if ((icmpType < 0)||(icmpType > 0xff)) + return [ args[0][1],args[0][2],'Missing or invalid ICMP type.' ]; let icmpCode = _parseNum(args[1][0]); // -1 okay, indicates don't match code if (icmpCode > 0xff) - return [args[1][1], args[1][2], 'Invalid ICMP code (use -1 for none).']; + return [ args[1][1],args[1][2],'Invalid ICMP code (use -1 for none).' ]; rules.push({ 'type': 'MATCH_ICMP', 'not': not, @@ -405,7 +410,7 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'icmpType': icmpType, 'icmpCode': ((icmpCode < 0) ? null : icmpCode) }); - } break; + } break; case 'sport': case 'dport': @@ -416,7 +421,7 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { if (arg.indexOf('-') > 0) { let asplit = arg.split('-'); if (asplit.length !== 2) { - return [args[0][1], args[0][2], 'Invalid numeric range.']; + return [ args[0][1],args[0][2],'Invalid numeric range.' ]; } else { fn = _parseNum(asplit[0]); tn = _parseNum(asplit[1]); @@ -425,8 +430,8 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { fn = _parseNum(arg); tn = fn; } - if ((fn < 0) || (fn > 0xffff) || (tn < 0) || (tn > 0xffff) || (tn < fn)) - return [args[0][1], args[0][2], 'Invalid numeric range.']; + if ((fn < 0)||(fn > 0xffff)||(tn < 0)||(tn > 0xffff)||(tn < fn)) + return [ args[0][1],args[0][2],'Invalid numeric range.' ]; rules.push({ 'type': KEYWORD_TO_API_MAP[match], 'not': not, @@ -434,19 +439,19 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'start': fn, 'end': tn }); - } break; + } break; case 'iptos': { let mask = _parseNum(args[0][0]); - if ((typeof mask !== 'number') || (mask < 0) || (mask > 0xff) || (mask === null)) - return [args[0][1], args[0][2], 'Invalid mask.']; + if ((typeof mask !== 'number')||(mask < 0)||(mask > 0xff)||(mask === null)) + return [ args[0][1],args[0][2],'Invalid mask.' ]; let arg = args[1][0]; let fn = null; let tn = null; if (arg.indexOf('-') > 0) { let asplit = arg.split('-'); if (asplit.length !== 2) { - return [args[1][1], args[1][2], 'Invalid value range.']; + return [ args[1][1],args[1][2],'Invalid value range.' ]; } else { fn = _parseNum(asplit[0]); tn = _parseNum(asplit[1]); @@ -455,8 +460,8 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { fn = _parseNum(arg); tn = fn; } - if ((fn < 0) || (fn > 0xff) || (tn < 0) || (tn > 0xff) || (tn < fn)) - return [args[1][1], args[1][2], 'Invalid value range.']; + if ((fn < 0)||(fn > 0xff)||(tn < 0)||(tn > 0xff)||(tn < fn)) + return [ args[1][1],args[1][2],'Invalid value range.' ]; rules.push({ 'type': 'MATCH_IP_TOS', 'not': not, @@ -465,18 +470,18 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'start': fn, 'end': tn }); - } break; + } break; case 'chr': { let chrb = args[0][0].split(/[,]+/); let maskhi = 0; let masklo = 0; - for (let i = 0; i < chrb.length; ++i) { + for(let i=0;i 0) { let tmp = CHARACTERISTIC_BITS[chrb[i]]; let bit = (typeof tmp === 'number') ? tmp : _parseNum(chrb[i]); - if ((bit < 0) || (bit > 63)) - return [args[0][1], args[0][2], 'Invalid bit index (range 0-63) or unrecognized name.']; + if ((bit < 0)||(bit > 63)) + return [ args[0][1],args[0][2],'Invalid bit index (range 0-63) or unrecognized name.' ]; if (bit >= 32) maskhi |= Math.abs(1 << (bit - 32)); else masklo |= Math.abs(1 << bit); @@ -492,7 +497,7 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'or': or, 'mask': (maskhi + masklo) }); - } break; + } break; case 'tand': case 'tor': @@ -516,10 +521,10 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { tagId = _parseNum(args[0][0]); tagValue = _parseNum(args[1][0]); } - if ((tagId < 0) || (tagId > 0xffffffff)) - return [args[0][1], args[0][2], 'Undefined tag name and invalid tag value.']; - if ((tagValue < 0) || (tagValue > 0xffffffff)) - return [args[1][1], args[1][2], 'Invalid tag value or unrecognized flag/enum name.']; + if ((tagId < 0)||(tagId > 0xffffffff)) + return [ args[0][1],args[0][2],'Undefined tag name and invalid tag value.' ]; + if ((tagValue < 0)||(tagValue > 0xffffffff)) + return [ args[1][1],args[1][2],'Invalid tag value or unrecognized flag/enum name.' ]; rules.push({ 'type': KEYWORD_TO_API_MAP[match], 'not': not, @@ -527,7 +532,7 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { 'id': tagId, 'value': tagValue }); - } break; + } break; } not = false; @@ -537,14 +542,15 @@ function _renderMatches(mtree, rules, macros, caps, tags, params) { return null; } -function _renderActions(rtree, rules, macros, caps, tags, params) { - for (let k = 0; k < rtree.length; ++k) { +function _renderActions(rtree,rules,macros,caps,tags,params) +{ + for(let k=0;k= rtree.length) - return [rtree[k][1], rtree[k][2], 'Include directive is missing a macro name.']; + return [ rtree[k][1],rtree[k][2],'Include directive is missing a macro name.' ]; let macroName = rtree[k + 1][0]; ++k; @@ -552,47 +558,47 @@ function _renderActions(rtree, rules, macros, caps, tags, params) { let parenIdx = macroName.indexOf('('); if (parenIdx > 0) { let pns = macroName.substr(parenIdx + 1).split(/[,)]+/); - for (let k = 0; k < pns.length; ++k) { + for(let k=0;k 0) macroParamArray.push(pns[k]); } - macroName = macroName.substr(0, parenIdx); + macroName = macroName.substr(0,parenIdx); } let macro = macros[macroName]; if (!macro) - return [rtree[k][1], rtree[k][2], 'Macro name not found.']; + return [ rtree[k][1],rtree[k][2],'Macro name not found.' ]; let macroParams = {}; - for (let param in macro.params) { + for(let param in macro.params) { let pidx = macro.params[param]; if (pidx >= macroParamArray.length) - return [rtree[k][1], rtree[k][2], 'Missing one or more required macro parameter.']; + return [ rtree[k][1],rtree[k][2],'Missing one or more required macro parameter.' ]; macroParams[param] = macroParamArray[pidx]; } - let err = _renderActions(macro.rules, rules, macros, caps, tags, macroParams); + let err = _renderActions(macro.rules,rules,macros,caps,tags,macroParams); if (err !== null) return err; - } else if ((action === 'drop') || (action === 'accept') || (action === 'break')) { // actions without arguments - if (((k + 1) < rtree.length) && (Array.isArray(rtree[k + 1][0]))) { + } else if ((action === 'drop')||(action === 'accept')||(action === 'break')) { // actions without arguments + if (((k + 1) < rtree.length)&&(Array.isArray(rtree[k + 1][0]))) { let mtree = rtree[k + 1]; ++k; - let err = _renderMatches(mtree, rules, macros, caps, tags, params); + let err = _renderMatches(mtree,rules,macros,caps,tags,params); if (err !== null) return err; } rules.push({ 'type': KEYWORD_TO_API_MAP[action] }); - } else if ((action === 'tee') || (action === 'watch')) { // actions with arguments (ZeroTier address) - if (((k + 1) < rtree.length) && (Array.isArray(rtree[k + 1][0])) && (rtree[k + 1][0].length >= 2)) { + } else if ((action === 'tee')||(action === 'watch')) { // actions with arguments (ZeroTier address) + if (((k + 1) < rtree.length)&&(Array.isArray(rtree[k + 1][0]))&&(rtree[k + 1][0].length >= 2)) { let mtree = rtree[k + 1]; ++k; let maxLength = _parseNum(mtree[0][0]); - if ((maxLength < -1) || (maxLength > 0xffff)) - return [mtree[0][1], mtree[1][2], 'Tee/watch max packet length to forward invalid or out of range.']; + if ((maxLength < -1)||(maxLength > 0xffff)) + return [ mtree[0][1],mtree[1][2],'Tee/watch max packet length to forward invalid or out of range.' ]; let target = mtree[1][0]; - if ((typeof target !== 'string') || (target.length !== 10)) - return [mtree[1][1], mtree[1][2], 'Missing or invalid ZeroTier address target for tee/watch.']; - let err = _renderMatches(mtree.slice(2), rules, macros, caps, tags, params); + if ((typeof target !== 'string')||(target.length !== 10)) + return [ mtree[1][1],mtree[1][2],'Missing or invalid ZeroTier address target for tee/watch.' ]; + let err = _renderMatches(mtree.slice(2),rules,macros,caps,tags,params); if (err !== null) return err; rules.push({ @@ -601,15 +607,15 @@ function _renderActions(rtree, rules, macros, caps, tags, params) { 'length': maxLength }); } else { - return [rtree[k][1], rtree[k][2], 'The tee and watch actions require two paremters (max length or 0 for all, target).']; + return [ rtree[k][1],rtree[k][2],'The tee and watch actions require two paremters (max length or 0 for all, target).' ]; } } else if (action === 'redirect') { - if (((k + 1) < rtree.length) && (Array.isArray(rtree[k + 1][0])) && (rtree[k + 1][0].length >= 1)) { + if (((k + 1) < rtree.length)&&(Array.isArray(rtree[k + 1][0]))&&(rtree[k + 1][0].length >= 1)) { let mtree = rtree[k + 1]; ++k; let target = mtree[0][0]; - if ((typeof target !== 'string') || (target.length !== 10)) - return [mtree[0][1], mtree[0][2], 'Missing or invalid ZeroTier address target for redirect.']; - let err = _renderMatches(mtree.slice(1), rules, macros, caps, tags, params); + if ((typeof target !== 'string')||(target.length !== 10)) + return [ mtree[0][1],mtree[0][2],'Missing or invalid ZeroTier address target for redirect.' ]; + let err = _renderMatches(mtree.slice(1),rules,macros,caps,tags,params); if (err !== null) return err; rules.push({ @@ -617,38 +623,39 @@ function _renderActions(rtree, rules, macros, caps, tags, params) { 'address': target }); } else { - return [rtree[k][1], rtree[k][2], 'The redirect action requires a target parameter.']; + return [ rtree[k][1],rtree[k][2],'The redirect action requires a target parameter.' ]; } } else { - return [rtree[k][1], rtree[k][2], 'Unrecognized action or directive in rule set.']; + return [ rtree[k][1],rtree[k][2],'Unrecognized action or directive in rule set.' ]; } } return null; } -function compile(src, rules, caps, tags) { +function compile(src,rules,caps,tags) +{ try { if (typeof src !== 'string') - return [0, 0, '"src" parameter must be a string.']; + return [ 0,0,'"src" parameter must be a string.' ]; // Pass 1: parse source into a tree of arrays of elements. Each element is a 3-item // tuple consisting of string, line number, and character index in line to enable // informative error messages to be returned. - var blockStack = [[]]; - var curr = ['', -1, -1]; + var blockStack = [ [] ]; + var curr = [ '',-1,-1 ]; var skipRestOfLine = false; - for (let idx = 0, lineNo = 1, lineIdx = 0; idx < src.length; ++idx, ++lineIdx) { + for(let idx=0,lineNo=1,lineIdx=0;idx 0) { blockStack[blockStack.length - 1].push(curr); } - if ((endOfBlock) && (blockStack.length > 1) && (blockStack[blockStack.length - 1].length > 0)) { + if ((endOfBlock)&&(blockStack.length > 1)&&(blockStack[blockStack.length - 1].length > 0)) { blockStack[blockStack.length - 2].push(blockStack[blockStack.length - 1]); blockStack.pop(); } else if (curr[0] in OPEN_BLOCK_KEYWORDS) { blockStack.push([]); } - curr = ['', -1, -1]; + curr = [ '',-1,-1 ]; } break; default: @@ -693,11 +700,11 @@ function compile(src, rules, caps, tags) { if (curr[0].length > 0) { if (curr[0].charAt(curr[0].length - 1) === ';') - curr[0] = curr[0].substr(0, curr[0].length - 1); + curr[0] = curr[0].substr(0,curr[0].length - 1); if (curr[0].length > 0) blockStack[blockStack.length - 1].push(curr); } - while ((blockStack.length > 1) && (blockStack[blockStack.length - 1].length > 0)) { + while ((blockStack.length > 1)&&(blockStack[blockStack.length - 1].length > 0)) { blockStack[blockStack.length - 2].push(blockStack[blockStack.length - 1]); blockStack.pop(); } @@ -707,13 +714,13 @@ function compile(src, rules, caps, tags) { let baseRuleTree = []; let macros = {}; - for (let i = 0; i < parsed.length; ++i) { + for(let i=0;i= parsed.length) || (!Array.isArray(parsed[i + 1])) || (parsed[i + 1].length < 1) || (!Array.isArray(parsed[i + 1][0]))) - return [parsed[i][1], parsed[i][2], 'Macro definition is missing name.']; + if ( ((i + 1) >= parsed.length) || (!Array.isArray(parsed[i + 1])) || (parsed[i + 1].length < 1) || (!Array.isArray(parsed[i + 1][0])) ) + return [ parsed[i][1],parsed[i][2],'Macro definition is missing name.' ]; let macro = parsed[++i]; let macroName = macro[0][0].toLowerCase(); @@ -721,20 +728,20 @@ function compile(src, rules, caps, tags) { let parenIdx = macroName.indexOf('('); if (parenIdx > 0) { let pns = macroName.substr(parenIdx + 1).split(/[,)]+/); - for (let k = 0; k < pns.length; ++k) { + for(let k=0;k 0) params[pns[k]] = k; } - macroName = macroName.substr(0, parenIdx); + macroName = macroName.substr(0,parenIdx); } if (!_isValidName(macroName)) - return [macro[0][1], macro[0][2], 'Invalid macro name.']; + return [ macro[0][1],macro[0][2],'Invalid macro name.' ]; if (macroName in RESERVED_WORDS) - return [macro[0][1], macro[0][2], 'Macro name is a reserved word.']; + return [ macro[0][1],macro[0][2],'Macro name is a reserved word.' ]; if (macroName in macros) - return [macro[0][1], macro[0][2], 'Multiple definition of macro name.']; + return [ macro[0][1],macro[0][2],'Multiple definition of macro name.' ]; macros[macroName] = { params: params, @@ -743,81 +750,81 @@ function compile(src, rules, caps, tags) { } else if (keyword === 'tag') { // Define tags - if (((i + 1) >= parsed.length) || (!Array.isArray(parsed[i + 1])) || (parsed[i + 1].length < 1) || (!Array.isArray(parsed[i + 1][0]))) - return [parsed[i][1], parsed[i][2], 'Tag definition is missing name.']; + if ( ((i + 1) >= parsed.length) || (!Array.isArray(parsed[i + 1])) || (parsed[i + 1].length < 1) || (!Array.isArray(parsed[i + 1][0])) ) + return [ parsed[i][1],parsed[i][2],'Tag definition is missing name.' ]; let tag = parsed[++i]; let tagName = tag[0][0].toLowerCase(); if (!_isValidName(tagName)) - return [tag[0][1], tag[0][2], 'Invalid tag name.']; + return [ tag[0][1],tag[0][2],'Invalid tag name.' ]; if (tagName in RESERVED_WORDS) - return [tag[0][1], tag[0][2], 'Tag name is a reserved word.']; + return [ tag[0][1],tag[0][2],'Tag name is a reserved word.' ]; if (tagName in tags) - return [tag[0][1], tag[0][2], 'Multiple definition of tag name.']; + return [ tag[0][1],tag[0][2],'Multiple definition of tag name.' ]; let flags = {}; let enums = {}; let id = -1; let dfl = null; - for (let k = 1; k < tag.length; ++k) { + for(let k=1;k= 0) - return [tag[k][1], tag[k][2], 'Duplicate tag id definition.']; + return [ tag[k][1],tag[k][2],'Duplicate tag id definition.' ]; if ((k + 1) >= tag.length) - return [tag[k][1], tag[k][2], 'Missing numeric value for ID.']; + return [ tag[k][1],tag[k][2],'Missing numeric value for ID.' ]; id = _parseNum(tag[++k][0]); - if ((id < 0) || (id > 0xffffffff)) - return [tag[k][1], tag[k][2], 'Invalid or out of range tag ID.']; + if ((id < 0)||(id > 0xffffffff)) + return [ tag[k][1],tag[k][2],'Invalid or out of range tag ID.' ]; } else if (tkeyword === 'default') { if (dfl !== null) - return [tag[k][1], tag[k][2], 'Duplicate tag default directive.']; + return [ tag[k][1],tag[k][2],'Duplicate tag default directive.' ]; if ((k + 1) >= tag.length) - return [tag[k][1], tag[k][2], 'Missing value for default.']; + return [ tag[k][1],tag[k][2],'Missing value for default.' ]; dfl = tag[++k][0]; } else if (tkeyword === 'flag') { if ((k + 2) >= tag.length) - return [tag[k][1], tag[k][2], 'Missing tag flag name or bit index.']; + return [ tag[k][1],tag[k][2],'Missing tag flag name or bit index.' ]; ++k; let bits = tag[k][0].split(/[,]+/); let mask = 0; - for (let j = 0; j < bits.length; ++j) { + for(let j=0;j 31)) - return [tag[k][1], tag[k][2], 'Bit index invalid, out of range, or references an undefined flag name.']; + if ((b < 0)||(b > 31)) + return [ tag[k][1],tag[k][2],'Bit index invalid, out of range, or references an undefined flag name.' ]; mask |= (1 << b); } } let flagName = tag[++k][0].toLowerCase(); if (!_isValidName(flagName)) - return [tag[k][1], tag[k][2], 'Invalid or reserved flag name.']; + return [ tag[k][1],tag[k][2],'Invalid or reserved flag name.' ]; if (flagName in flags) - return [tag[k][1], tag[k][2], 'Duplicate flag name in tag definition.']; + return [ tag[k][1],tag[k][2],'Duplicate flag name in tag definition.' ]; flags[flagName] = mask; } else if (tkeyword === 'enum') { if ((k + 2) >= tag.length) - return [tag[k][1], tag[k][2], 'Missing tag enum name or value.']; + return [ tag[k][1],tag[k][2],'Missing tag enum name or value.' ]; ++k; let value = _parseNum(tag[k][0]); - if ((value < 0) || (value > 0xffffffff)) - return [tag[k][1], tag[k][2], 'Tag enum value invalid or out of range.']; + if ((value < 0)||(value > 0xffffffff)) + return [ tag[k][1],tag[k][2],'Tag enum value invalid or out of range.' ]; let enumName = tag[++k][0].toLowerCase(); if (!_isValidName(enumName)) - return [tag[k][1], tag[k][2], 'Invalid or reserved tag enum name.']; + return [ tag[k][1],tag[k][2],'Invalid or reserved tag enum name.' ]; if (enumName in enums) - return [tag[k][1], tag[k][2], 'Duplicate enum name in tag definition.']; + return [ tag[k][1],tag[k][2],'Duplicate enum name in tag definition.' ]; enums[enumName] = value; } else { - return [tag[k][1], tag[k][2], 'Unrecognized keyword in tag definition.']; + return [ tag[k][1],tag[k][2],'Unrecognized keyword in tag definition.' ]; } } if (id < 0) - return [tag[0][1], tag[0][2], 'Tag definition is missing a numeric ID.']; + return [ tag[0][1],tag[0][2],'Tag definition is missing a numeric ID.' ]; if (typeof dfl === 'string') { let dfl2 = enums[dfl]; @@ -828,7 +835,7 @@ function compile(src, rules, caps, tags) { if (typeof dfl2 === 'number') { dfl = dfl2; } else { - dfl = Math.abs(parseInt(dfl) || 0) & 0xffffffff; + dfl = Math.abs(parseInt(dfl)||0) & 0xffffffff; } } } else if (typeof dfl === 'number') { @@ -844,35 +851,35 @@ function compile(src, rules, caps, tags) { } else if (keyword === 'cap') { // Define capabilities - if (((i + 1) >= parsed.length) || (!Array.isArray(parsed[i + 1])) || (parsed[i + 1].length < 1) || (!Array.isArray(parsed[i + 1][0]))) - return [parsed[i][1], parsed[i][2], 'Capability definition is missing name.']; + if ( ((i + 1) >= parsed.length) || (!Array.isArray(parsed[i + 1])) || (parsed[i + 1].length < 1) || (!Array.isArray(parsed[i + 1][0])) ) + return [ parsed[i][1],parsed[i][2],'Capability definition is missing name.' ]; let cap = parsed[++i]; let capName = cap[0][0].toLowerCase(); if (!_isValidName(capName)) - return [cap[0][1], cap[0][2], 'Invalid capability name.']; + return [ cap[0][1],cap[0][2],'Invalid capability name.' ]; if (capName in RESERVED_WORDS) - return [cap[0][1], cap[0][2], 'Capability name is a reserved word.']; + return [ cap[0][1],cap[0][2],'Capability name is a reserved word.' ]; if (capName in caps) - return [cap[0][1], cap[0][2], 'Multiple definition of capability name.']; + return [ cap[0][1],cap[0][2],'Multiple definition of capability name.' ]; let capRules = []; let id = -1; let dfl = false; - for (let k = 1; k < cap.length; ++k) { + for(let k=1;k= 0) - return [cap[k][1], cap[k][2], 'Duplicate id directive in capability definition.']; + return [ cap[k][1],cap[k][2],'Duplicate id directive in capability definition.' ]; if ((k + 1) >= cap.length) - return [cap[k][1], cap[k][2], 'Missing value for ID.']; + return [ cap[k][1],cap[k][2],'Missing value for ID.' ]; id = _parseNum(cap[++k][0]); - if ((id < 0) || (id > 0xffffffff)) - return [cap[k - 1][1], cap[k - 1][2], 'Invalid or out of range capability ID.']; - for (let cn in caps) { + if ((id < 0)||(id > 0xffffffff)) + return [ cap[k - 1][1],cap[k - 1][2],'Invalid or out of range capability ID.' ]; + for(let cn in caps) { if (caps[cn].id === id) - return [cap[k - 1][1], cap[k - 1][2], 'Duplicate capability ID.']; + return [ cap[k - 1][1],cap[k - 1][2],'Duplicate capability ID.' ]; } } else if (dn === 'default') { dfl = true; @@ -881,7 +888,7 @@ function compile(src, rules, caps, tags) { } } if (id < 0) - return [cap[0][1], cap[0][2], 'Capability definition is missing a numeric ID.']; + return [ cap[0][1],cap[0][2],'Capability definition is missing a numeric ID.' ]; caps[capName] = { 'id': id, @@ -895,22 +902,22 @@ function compile(src, rules, caps, tags) { // Pass 3: render low-level ZeroTier rules arrays for capabilities and base. - for (let capName in caps) { + for(let capName in caps) { let r = []; - let err = _renderActions(caps[capName].rules, r, macros, caps, tags, {}); + let err = _renderActions(caps[capName].rules,r,macros,caps,tags,{}); if (err !== null) return err; caps[capName].rules = r; } - let err = _renderActions(baseRuleTree, rules, macros, caps, tags, {}); + let err = _renderActions(baseRuleTree,rules,macros,caps,tags,{}); if (err !== null) return err; return null; } catch (e) { console.log(e.stack); - return [0, 0, 'Unexpected exception: ' + e.toString()]; + return [ 0,0,'Unexpected exception: '+e.toString() ]; } } diff --git a/attic/service/CMakeLists.txt b/attic/service/CMakeLists.txt new file mode 100644 index 00000000..bebfb2cd --- /dev/null +++ b/attic/service/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8) +project(zt_service) + +if(WIN32) + add_definitions(-DNOMINMAX) +endif(WIN32) + +set(src + OneService.cpp +) + +set(headers + OneService.hpp +) + +add_library(${PROJECT_NAME} STATIC ${src} ${headers}) +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) diff --git a/attic/service/OneService.cpp b/attic/service/OneService.cpp new file mode 100644 index 00000000..e84da792 --- /dev/null +++ b/attic/service/OneService.cpp @@ -0,0 +1,2253 @@ +/* + * 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. + */ +/****/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/ZeroTierCore.h" + +#include "../node/Constants.hpp" +#include "../node/Mutex.hpp" +#include "../node/Node.hpp" +#include "../node/Utils.hpp" +#include "../node/InetAddress.hpp" +#include "../node/MAC.hpp" +#include "../node/Identity.hpp" +#include "../node/Salsa20.hpp" +#include "../node/Poly1305.hpp" +#include "../node/SHA512.hpp" + +#include "../osdep/Phy.hpp" +#include "../osdep/Thread.hpp" +#include "../osdep/OSUtils.hpp" +#include "../osdep/Http.hpp" +#include "../osdep/PortMapper.hpp" +#include "../osdep/Binder.hpp" +#include "../osdep/ManagedRoute.hpp" +#include "../osdep/BlockingQueue.hpp" + +#include "OneService.hpp" + +#ifdef __WINDOWS__ +#include +#include +#include +#include +#include +//#include +#define stat _stat +#else +#include +#include +#include +#include +#include +#include +#endif + +#ifdef ZT_USE_SYSTEM_HTTP_PARSER +#include +#else +#include "../ext/http-parser/http_parser.h" +#endif + +#include "../ext/json/json.hpp" + +using json = nlohmann::json; + +#include "../controller/EmbeddedNetworkController.hpp" +#include "../controller/RabbitMQ.hpp" +#include "../osdep/EthernetTap.hpp" +#ifdef __WINDOWS__ +#include "../osdep/WindowsEthernetTap.hpp" +#endif + +// Sanity limits for HTTP +#define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 64) +#define ZT_MAX_HTTP_CONNECTIONS 65536 + +// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also +// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi. +#define ZT_IF_METRIC 5000 + +// How often to check for new multicast subscriptions on a tap device +#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000 + +// How often to check for local interface addresses +#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 + +// How often local.conf is checked for changes +#define ZT_LOCAL_CONF_FILE_CHECK_INTERVAL 10000 + +namespace ZeroTier { + +namespace { + +static void _networkToJson(nlohmann::json &nj,const ZT_VirtualNetworkConfig *nc,const std::string &portDeviceName,const OneService::NetworkSettings &localSettings) +{ + char tmp[256]; + + const char *nstatus = "",*ntype = ""; + switch(nc->status) { + case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: nstatus = "REQUESTING_CONFIGURATION"; break; + case ZT_NETWORK_STATUS_OK: nstatus = "OK"; break; + case ZT_NETWORK_STATUS_ACCESS_DENIED: nstatus = "ACCESS_DENIED"; break; + case ZT_NETWORK_STATUS_NOT_FOUND: nstatus = "NOT_FOUND"; break; + case ZT_NETWORK_STATUS_PORT_ERROR: nstatus = "PORT_ERROR"; break; + case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: nstatus = "CLIENT_TOO_OLD"; break; + } + switch(nc->type) { + case ZT_NETWORK_TYPE_PRIVATE: ntype = "PRIVATE"; break; + case ZT_NETWORK_TYPE_PUBLIC: ntype = "PUBLIC"; break; + } + + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",nc->nwid); + nj["id"] = tmp; + nj["nwid"] = tmp; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)((nc->mac >> 40) & 0xff),(unsigned int)((nc->mac >> 32) & 0xff),(unsigned int)((nc->mac >> 24) & 0xff),(unsigned int)((nc->mac >> 16) & 0xff),(unsigned int)((nc->mac >> 8) & 0xff),(unsigned int)(nc->mac & 0xff)); + nj["mac"] = tmp; + nj["name"] = nc->name; + nj["status"] = nstatus; + nj["type"] = ntype; + nj["mtu"] = nc->mtu; + nj["dhcp"] = (bool)(nc->dhcp != 0); + nj["bridge"] = (bool)(nc->bridge != 0); + nj["broadcastEnabled"] = (bool)(nc->broadcastEnabled != 0); + nj["portError"] = nc->portError; + nj["netconfRevision"] = nc->netconfRevision; + nj["portDeviceName"] = portDeviceName; + nj["allowManaged"] = localSettings.allowManaged; + nj["allowGlobal"] = localSettings.allowGlobal; + nj["allowDefault"] = localSettings.allowDefault; + + nlohmann::json aa = nlohmann::json::array(); + for(unsigned int i=0;iassignedAddressCount;++i) { + aa.push_back(reinterpret_cast(&(nc->assignedAddresses[i]))->toString(tmp)); + } + nj["assignedAddresses"] = aa; + + nlohmann::json ra = nlohmann::json::array(); + for(unsigned int i=0;irouteCount;++i) { + nlohmann::json rj; + rj["target"] = reinterpret_cast(&(nc->routes[i].target))->toString(tmp); + if (nc->routes[i].via.ss_family == nc->routes[i].target.ss_family) + rj["via"] = reinterpret_cast(&(nc->routes[i].via))->toIpString(tmp); + else rj["via"] = nlohmann::json(); + rj["flags"] = (int)nc->routes[i].flags; + rj["metric"] = (int)nc->routes[i].metric; + ra.push_back(rj); + } + nj["routes"] = ra; + + nlohmann::json mca = nlohmann::json::array(); + for(unsigned int i=0;imulticastSubscriptionCount;++i) { + nlohmann::json m; + m["mac"] = MAC(nc->multicastSubscriptions[i].mac).toString(tmp); + m["adi"] = nc->multicastSubscriptions[i].adi; + mca.push_back(m); + } + nj["multicastSubscriptions"] = mca; +} + +static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) +{ + char tmp[256]; + + const char *prole = ""; + switch(peer->role) { + case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break; + case ZT_PEER_ROLE_MOON: prole = "MOON"; break; + case ZT_PEER_ROLE_PLANET: prole = "PLANET"; break; + } + + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",peer->address); + pj["address"] = tmp; + pj["versionMajor"] = peer->versionMajor; + pj["versionMinor"] = peer->versionMinor; + pj["versionRev"] = peer->versionRev; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%d.%d.%d",peer->versionMajor,peer->versionMinor,peer->versionRev); + pj["version"] = tmp; + pj["latency"] = peer->latency; + pj["role"] = prole; + + nlohmann::json pa = nlohmann::json::array(); + for(unsigned int i=0;ipathCount;++i) { + int64_t lastSend = peer->paths[i].lastSend; + int64_t lastReceive = peer->paths[i].lastReceive; + nlohmann::json j; + j["address"] = reinterpret_cast(&(peer->paths[i].address))->toString(tmp); + j["lastSend"] = (lastSend < 0) ? 0 : lastSend; + j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive; + j["trustedPathId"] = peer->paths[i].trustedPathId; + j["active"] = (bool)(peer->paths[i].expired == 0); + j["expired"] = (bool)(peer->paths[i].expired != 0); + j["preferred"] = (bool)(peer->paths[i].preferred != 0); + pa.push_back(j); + } + pj["paths"] = pa; +} + +static void _peerAggregateLinkToJson(nlohmann::json &pj,const ZT_Peer *peer) +{ + char tmp[256]; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",peer->address); + pj["aggregateLinkLatency"] = peer->latency; + + nlohmann::json pa = nlohmann::json::array(); + for(unsigned int i=0;ipathCount;++i) { + int64_t lastSend = peer->paths[i].lastSend; + int64_t lastReceive = peer->paths[i].lastReceive; + nlohmann::json j; + j["address"] = reinterpret_cast(&(peer->paths[i].address))->toString(tmp); + j["lastSend"] = (lastSend < 0) ? 0 : lastSend; + j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive; + //j["trustedPathId"] = peer->paths[i].trustedPathId; + //j["active"] = (bool)(peer->paths[i].expired == 0); + //j["expired"] = (bool)(peer->paths[i].expired != 0); + //j["preferred"] = (bool)(peer->paths[i].preferred != 0); + j["latency"] = peer->paths[i].latency; + j["pdv"] = peer->paths[i].packetDelayVariance; + //j["throughputDisturbCoeff"] = peer->paths[i].throughputDisturbCoeff; + //j["packetErrorRatio"] = peer->paths[i].packetErrorRatio; + //j["packetLossRatio"] = peer->paths[i].packetLossRatio; + j["stability"] = peer->paths[i].stability; + j["throughput"] = peer->paths[i].throughput; + //j["maxThroughput"] = peer->paths[i].maxThroughput; + j["allocation"] = peer->paths[i].allocation; + j["ifname"] = peer->paths[i].ifname; + pa.push_back(j); + } + pj["paths"] = pa; +} + +class OneServiceImpl; + +static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); +static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); +static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len); +static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen); +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); +static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr); +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); +static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); + +static int ShttpOnMessageBegin(http_parser *parser); +static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); +#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) +static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); +#else +static int ShttpOnStatus(http_parser *parser); +#endif +static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnHeadersComplete(http_parser *parser); +static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnMessageComplete(http_parser *parser); + +#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) +static const struct http_parser_settings HTTP_PARSER_SETTINGS = { + ShttpOnMessageBegin, + ShttpOnUrl, + ShttpOnStatus, + ShttpOnHeaderField, + ShttpOnValue, + ShttpOnHeadersComplete, + ShttpOnBody, + ShttpOnMessageComplete +}; +#else +static const struct http_parser_settings HTTP_PARSER_SETTINGS = { + ShttpOnMessageBegin, + ShttpOnUrl, + ShttpOnHeaderField, + ShttpOnValue, + ShttpOnHeadersComplete, + ShttpOnBody, + ShttpOnMessageComplete +}; +#endif + +/** + * A TCP connection and related state and buffers + */ +struct TcpConnection +{ + enum { + TCP_UNCATEGORIZED_INCOMING, // uncategorized incoming connection + TCP_HTTP_INCOMING, + } type; + + OneServiceImpl *parent; + PhySocket *sock; + InetAddress remoteAddr; + uint64_t lastReceive; + + // Used for inbound HTTP connections + http_parser parser; + unsigned long messageSize; + std::string currentHeaderField; + std::string currentHeaderValue; + std::string url; + std::string status; + std::map< std::string,std::string > headers; + + std::string readq; + std::string writeq; + Mutex writeq_m; +}; + +class OneServiceImpl : public OneService +{ +public: + // begin member variables -------------------------------------------------- + + const std::string _homePath; + std::string _authToken; + std::string _controllerDbPath; + const std::string _networksPath; + const std::string _moonsPath; + + EmbeddedNetworkController *_controller; + Phy _phy; + Node *_node; + PhySocket *_localControlSocket4; + PhySocket *_localControlSocket6; + bool _updateAutoApply; + bool _allowSecondaryPort; + unsigned int _multipathMode; + unsigned int _primaryPort; + unsigned int _secondaryPort; + unsigned int _tertiaryPort; + + // Local configuration and memo-ized information from it + json _localConfig; + Hashtable< uint64_t,std::vector > _v4Hints; + Hashtable< uint64_t,std::vector > _v6Hints; + Hashtable< uint64_t,std::vector > _v4Blacklists; + Hashtable< uint64_t,std::vector > _v6Blacklists; + std::vector< InetAddress > _globalV4Blacklist; + std::vector< InetAddress > _globalV6Blacklist; + std::vector< InetAddress > _allowManagementFrom; + std::vector< std::string > _interfacePrefixBlacklist; + Mutex _localConfig_m; + + std::vector _explicitBind; + + /* + * To attempt to handle NAT/gateway craziness we use three local UDP ports: + * + * [0] is the normal/default port, usually 9993 + * [1] is a port derived from our ZeroTier address + * [2] is a port computed from the normal/default for use with uPnP/NAT-PMP mappings + * + * [2] exists because on some gateways trying to do regular NAT-t interferes + * destructively with uPnP port mapping behavior in very weird buggy ways. + * It's only used if uPnP/NAT-PMP is enabled in this build. + */ + unsigned int _ports[3]; + Binder _binder; + + // Time we last received a packet from a global address + uint64_t _lastDirectReceiveFromGlobal; + + // Last potential sleep/wake event + uint64_t _lastRestart; + + // Deadline for the next background task service function + volatile int64_t _nextBackgroundTaskDeadline; + + // Configured networks + struct NetworkState + { + NetworkState() : + tap((EthernetTap *)0) + { + // Real defaults are in network 'up' code in network event handler + settings.allowManaged = true; + settings.allowGlobal = false; + settings.allowDefault = false; + } + + std::shared_ptr tap; + ZT_VirtualNetworkConfig config; // memcpy() of raw config from core + std::vector managedIps; + std::list< SharedPtr > managedRoutes; + NetworkSettings settings; + }; + std::map _nets; + Mutex _nets_m; + + // Active TCP/IP connections + std::vector< TcpConnection * > _tcpConnections; + Mutex _tcpConnections_m; + + // Termination status information + ReasonForTermination _termReason; + std::string _fatalErrorMessage; + Mutex _termReason_m; + + // uPnP/NAT-PMP port mapper if enabled + bool _portMappingEnabled; // local.conf settings + PortMapper *_portMapper; + + // Set to false to force service to stop + volatile bool _run; + Mutex _run_m; + + MQConfig *_mqc; + + // end member variables ---------------------------------------------------- + + OneServiceImpl(const char *hp,unsigned int port) : + _homePath((hp) ? hp : ".") + ,_controllerDbPath(_homePath + ZT_PATH_SEPARATOR_S "controller.d") + ,_networksPath(_homePath + ZT_PATH_SEPARATOR_S "networks.d") + ,_moonsPath(_homePath + ZT_PATH_SEPARATOR_S "moons.d") + ,_controller((EmbeddedNetworkController *)0) + ,_phy(this,false,true) + ,_node((Node *)0) + ,_localControlSocket4((PhySocket *)0) + ,_localControlSocket6((PhySocket *)0) + ,_updateAutoApply(false) + ,_primaryPort(port) + ,_lastDirectReceiveFromGlobal(0) + ,_lastRestart(0) + ,_nextBackgroundTaskDeadline(0) + ,_termReason(ONE_STILL_RUNNING) + ,_portMappingEnabled(true) + ,_portMapper((PortMapper *)0) + ,_run(true) + ,_mqc(NULL) + { + _ports[0] = 0; + _ports[1] = 0; + _ports[2] = 0; + } + + virtual ~OneServiceImpl() + { + _binder.closeAll(_phy); + _phy.close(_localControlSocket4); + _phy.close(_localControlSocket6); + + delete _portMapper; + delete _controller; + delete _mqc; + } + + virtual ReasonForTermination run() + { + try { + { + const std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S "authtoken.secret"); + if (!OSUtils::readFile(authTokenPath.c_str(),_authToken)) { + unsigned char foo[24]; + Utils::getSecureRandom(foo,sizeof(foo)); + _authToken = ""; + for(unsigned int i=0;iaddress() % 45500) : _secondaryPort; + 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 (_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 (_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); + } + } + } + + // 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); + _node->setController((void *)_controller); + + // Join existing networks in networks.d + { + std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); + for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { + std::size_t dot = f->find_last_of('.'); + if ((dot == 16)&&(f->substr(16) == ".conf")) + _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0,(void *)0); + } + } + + // Main I/O loop + _nextBackgroundTaskDeadline = 0; + int64_t clockShouldBe = OSUtils::now(); + _lastRestart = clockShouldBe; + int64_t lastTapMulticastGroupCheck = 0; + int64_t lastBindRefresh = 0; + int64_t lastMultipathModeUpdate = 0; + int64_t lastCleanedPeersDb = 0; + int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle + int64_t lastLocalConfFileCheck = OSUtils::now(); + for(;;) { + _run_m.lock(); + if (!_run) { + _run_m.unlock(); + _termReason_m.lock(); + _termReason = ONE_NORMAL_TERMINATION; + _termReason_m.unlock(); + break; + } else { + _run_m.unlock(); + } + + const int64_t now = OSUtils::now(); + + // Attempt to detect sleep/wake events by detecting delay overruns + bool restarted = false; + if ((now > clockShouldBe)&&((now - clockShouldBe) > 10000)) { + _lastRestart = now; + restarted = true; + } + + // Reload local.conf if anything changed recently + if ((now - lastLocalConfFileCheck) >= ZT_LOCAL_CONF_FILE_CHECK_INTERVAL) { + lastLocalConfFileCheck = now; + struct stat result; + if(stat((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), &result)==0) { + int64_t mod_time = result.st_mtime * 1000; + if ((now - mod_time) <= ZT_LOCAL_CONF_FILE_CHECK_INTERVAL) { + readLocalSettings(); + applyLocalConfig(); + } + } + } + + // Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default) + if (((now - lastBindRefresh) >= (_multipathMode ? ZT_BINDER_REFRESH_PERIOD / 8 : ZT_BINDER_REFRESH_PERIOD))||(restarted)) { + lastBindRefresh = now; + unsigned int p[3]; + unsigned int pc = 0; + for(int i=0;i<3;++i) { + if (_ports[i]) + p[pc++] = _ports[i]; + } + _binder.refresh(_phy,p,pc,_explicitBind,*this); + { + Mutex::Lock _l(_nets_m); + for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) { + if (n->second.tap) + syncManagedStuff(n->second,false,true); + } + } + } + // Update multipath mode (if needed) + if (((now - lastMultipathModeUpdate) >= ZT_BINDER_REFRESH_PERIOD / 8)||(restarted)) { + lastMultipathModeUpdate = now; + _node->setMultipathMode(_multipathMode); + } + + // Run background task processor in core if it's time to do so + int64_t dl = _nextBackgroundTaskDeadline; + if (dl <= now) { + _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); + dl = _nextBackgroundTaskDeadline; + } + + // Sync multicast group memberships + if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) { + lastTapMulticastGroupCheck = now; + std::vector< std::pair< uint64_t,std::pair< std::vector,std::vector > > > mgChanges; + { + Mutex::Lock _l(_nets_m); + mgChanges.reserve(_nets.size() + 1); + for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { + if (n->second.tap) { + mgChanges.push_back(std::pair< uint64_t,std::pair< std::vector,std::vector > >(n->first,std::pair< std::vector,std::vector >())); + n->second.tap->scanMulticastGroups(mgChanges.back().second.first,mgChanges.back().second.second); + } + } + } + for(std::vector< std::pair< uint64_t,std::pair< std::vector,std::vector > > >::iterator c(mgChanges.begin());c!=mgChanges.end();++c) { + for(std::vector::iterator m(c->second.first.begin());m!=c->second.first.end();++m) + _node->multicastSubscribe((void *)0,c->first,m->mac().toInt(),m->adi()); + for(std::vector::iterator m(c->second.second.begin());m!=c->second.second.end();++m) + _node->multicastUnsubscribe(c->first,m->mac().toInt(),m->adi()); + } + } + + // Sync information about physical network interfaces + if ((now - lastLocalInterfaceAddressCheck) >= (_multipathMode ? ZT_LOCAL_INTERFACE_CHECK_INTERVAL / 8 : ZT_LOCAL_INTERFACE_CHECK_INTERVAL)) { + lastLocalInterfaceAddressCheck = now; + + _node->clearLocalInterfaceAddresses(); + + if (_portMapper) { + std::vector mappedAddresses(_portMapper->get()); + for(std::vector::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); + } + + std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); + for(std::vector::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) + _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); + } + + // Clean peers.d periodically + if ((now - lastCleanedPeersDb) >= 3600000) { + lastCleanedPeersDb = now; + OSUtils::cleanDirectory((_homePath + ZT_PATH_SEPARATOR_S "peers.d").c_str(),now - 2592000000LL); // delete older than 30 days + } + + const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100; + clockShouldBe = now + (uint64_t)delay; + _phy.poll(delay); + } + } catch (std::exception &e) { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = std::string("unexpected exception in main thread: ")+e.what(); + } catch ( ... ) { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = "unexpected exception in main thread: unknown exception"; + } + + try { + Mutex::Lock _l(_tcpConnections_m); + while (!_tcpConnections.empty()) + _phy.close((*_tcpConnections.begin())->sock); + } catch ( ... ) {} + + { + Mutex::Lock _l(_nets_m); + _nets.clear(); + } + + delete _node; + _node = (Node *)0; + + return _termReason; + } + + void readLocalSettings() + { + // Read local configuration + std::map ppc; + + // LEGACY: support old "trustedpaths" flat file + FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(),"r"); + if (trustpaths) { + fprintf(stderr,"WARNING: 'trustedpaths' flat file format is deprecated in favor of path definitions in local.conf" ZT_EOL_S); + char buf[1024]; + while (fgets(buf,sizeof(buf),trustpaths)) { + int fno = 0; + char *saveptr = (char *)0; + uint64_t trustedPathId = 0; + InetAddress trustedPathNetwork; + for(char *f=Utils::stok(buf,"=\r\n \t",&saveptr);(f);f=Utils::stok((char *)0,"=\r\n \t",&saveptr)) { + if (fno == 0) { + trustedPathId = Utils::hexStrToU64(f); + } else if (fno == 1) { + trustedPathNetwork = InetAddress(f); + } else break; + ++fno; + } + if ( (trustedPathId != 0) && ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathNetwork.netmaskBits() > 0) ) { + ppc[trustedPathNetwork].trustedPathId = trustedPathId; + ppc[trustedPathNetwork].mtu = 0; // use default + } + } + fclose(trustpaths); + } + + // Read local config file + Mutex::Lock _l2(_localConfig_m); + std::string lcbuf; + if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lcbuf)) { + if (lcbuf.length() > 0) { + try { + _localConfig = OSUtils::jsonParse(lcbuf); + if (!_localConfig.is_object()) { + fprintf(stderr,"ERROR: unable to parse local.conf (root element is not a JSON object)" ZT_EOL_S); + exit(1); + } + } catch ( ... ) { + fprintf(stderr,"ERROR: unable to parse local.conf (invalid JSON)" ZT_EOL_S); + exit(1); + } + } + } + + // Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere) + json &physical = _localConfig["physical"]; + if (physical.is_object()) { + for(json::iterator phy(physical.begin());phy!=physical.end();++phy) { + InetAddress net(OSUtils::jsonString(phy.key(),"").c_str()); + if (net) { + if (phy.value().is_object()) { + uint64_t tpid; + if ((tpid = OSUtils::jsonInt(phy.value()["trustedPathId"],0ULL)) != 0ULL) { + if ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) + ppc[net].trustedPathId = tpid; + } + ppc[net].mtu = (int)OSUtils::jsonInt(phy.value()["mtu"],0ULL); // 0 means use default + } + } + } + } + + json &settings = _localConfig["settings"]; + if (settings.is_object()) { + // Allow controller DB path to be put somewhere else + const std::string cdbp(OSUtils::jsonString(settings["controllerDbPath"],"")); + 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(); + } + + // Bind to wildcard instead of to specific interfaces (disables full tunnel capability) + json &bind = settings["bind"]; + if (bind.is_array()) { + for(unsigned long i=0;i 0) { + InetAddress ip(ips.c_str()); + if ((ip.ss_family == AF_INET)||(ip.ss_family == AF_INET6)) + _explicitBind.push_back(ip); + } + } + } + } + + // Set trusted paths if there are any + if (ppc.size() > 0) { + for(std::map::iterator i(ppc.begin());i!=ppc.end();++i) + _node->setPhysicalPathConfiguration(reinterpret_cast(&(i->first)),&(i->second)); + } + } + + virtual ReasonForTermination reasonForTermination() const + { + Mutex::Lock _l(_termReason_m); + return _termReason; + } + + virtual std::string fatalErrorMessage() const + { + Mutex::Lock _l(_termReason_m); + return _fatalErrorMessage; + } + + virtual std::string portDeviceName(uint64_t nwid) const + { + Mutex::Lock _l(_nets_m); + std::map::const_iterator n(_nets.find(nwid)); + if ((n != _nets.end())&&(n->second.tap)) + return n->second.tap->deviceName(); + else return std::string(); + } + +#ifdef ZT_SDK + virtual std::string givenHomePath() + { + return _homePath; + } + + void getRoutes(uint64_t nwid, void *routeArray, unsigned int *numRoutes) + { + Mutex::Lock _l(_nets_m); + NetworkState &n = _nets[nwid]; + *numRoutes = *numRoutes < n.config.routeCount ? *numRoutes : n.config.routeCount; + for(unsigned int i=0; i<*numRoutes; i++) { + ZT_VirtualNetworkRoute *vnr = (ZT_VirtualNetworkRoute*)routeArray; + memcpy(&vnr[i], &(n.config.routes[i]), sizeof(ZT_VirtualNetworkRoute)); + } + } + + virtual Node *getNode() + { + return _node; + } +#endif // ZT_SDK + + virtual void terminate() + { + _run_m.lock(); + _run = false; + _run_m.unlock(); + _phy.whack(); + } + + virtual bool getNetworkSettings(const uint64_t nwid,NetworkSettings &settings) const + { + Mutex::Lock _l(_nets_m); + std::map::const_iterator n(_nets.find(nwid)); + if (n == _nets.end()) + return false; + settings = n->second.settings; + return true; + } + + virtual bool setNetworkSettings(const uint64_t nwid,const NetworkSettings &settings) + { + Mutex::Lock _l(_nets_m); + + std::map::iterator n(_nets.find(nwid)); + if (n == _nets.end()) + return false; + n->second.settings = settings; + + char nlcpath[4096]; + OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_networksPath.c_str(),nwid); + FILE *out = fopen(nlcpath,"w"); + if (out) { + fprintf(out,"allowManaged=%d\n",(int)n->second.settings.allowManaged); + fprintf(out,"allowGlobal=%d\n",(int)n->second.settings.allowGlobal); + fprintf(out,"allowDefault=%d\n",(int)n->second.settings.allowDefault); + fclose(out); + } + + if (n->second.tap) + syncManagedStuff(n->second,true,true); + + return true; + } + + // ========================================================================= + // Internal implementation methods for control plane, route setup, etc. + // ========================================================================= + + inline unsigned int handleControlPlaneHttpRequest( + const InetAddress &fromAddress, + unsigned int httpMethod, + const std::string &path, + const std::map &headers, + const std::string &body, + std::string &responseBody, + std::string &responseContentType) + { + char tmp[256]; + unsigned int scode = 404; + json res; + std::vector ps(OSUtils::split(path.c_str(),"/","","")); + std::map urlArgs; + + /* Note: this is kind of restricted in what it'll take. It does not support + * URL encoding, and /'s in URL args will screw it up. But the only URL args + * it really uses in ?jsonp=funcionName, and otherwise it just takes simple + * paths to simply-named resources. */ + if (ps.size() > 0) { + std::size_t qpos = ps[ps.size() - 1].find('?'); + if (qpos != std::string::npos) { + std::string args(ps[ps.size() - 1].substr(qpos + 1)); + ps[ps.size() - 1] = ps[ps.size() - 1].substr(0,qpos); + std::vector asplit(OSUtils::split(args.c_str(),"&","","")); + for(std::vector::iterator a(asplit.begin());a!=asplit.end();++a) { + std::size_t eqpos = a->find('='); + if (eqpos == std::string::npos) + urlArgs[*a] = ""; + else urlArgs[a->substr(0,eqpos)] = a->substr(eqpos + 1); + } + } + } else { + return 404; + } + + bool isAuth = false; + { + std::map::const_iterator ah(headers.find("x-zt1-auth")); + if ((ah != headers.end())&&(_authToken == ah->second)) { + isAuth = true; + } else { + ah = urlArgs.find("auth"); + if ((ah != urlArgs.end())&&(_authToken == ah->second)) + isAuth = true; + } + } + +#ifdef __SYNOLOGY__ + // Authenticate via Synology's built-in cgi script + if (!isAuth) { + int synotoken_pos = path.find("SynoToken"); + int argpos = path.find("?"); + if(synotoken_pos != std::string::npos && argpos != std::string::npos) { + std::string cookie = path.substr(argpos+1, synotoken_pos-(argpos+1)); + std::string synotoken = path.substr(synotoken_pos); + std::string cookie_val = cookie.substr(cookie.find("=")+1); + std::string synotoken_val = synotoken.substr(synotoken.find("=")+1); + // Set necessary env for auth script + std::map::const_iterator ah2(headers.find("x-forwarded-for")); + setenv("HTTP_COOKIE", cookie_val.c_str(), true); + setenv("HTTP_X_SYNO_TOKEN", synotoken_val.c_str(), true); + setenv("REMOTE_ADDR", ah2->second.c_str(),true); + char user[256], buf[1024]; + FILE *fp = NULL; + bzero(user, 256); + fp = popen("/usr/syno/synoman/webman/modules/authenticate.cgi", "r"); + if(!fp) + isAuth = false; + else { + bzero(buf, sizeof(buf)); + fread(buf, 1024, 1, fp); + if(strlen(buf) > 0) { + snprintf(user, 256, "%s", buf); + isAuth = true; + } + } + pclose(fp); + } + } +#endif + + if (httpMethod == HTTP_GET) { + if (isAuth) { + if (ps[0] == "status") { + ZT_NodeStatus status; + _node->status(&status); + + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",status.address); + res["address"] = tmp; + res["publicIdentity"] = status.publicIdentity; + res["online"] = (bool)(status.online != 0); + res["versionMajor"] = ZEROTIER_ONE_VERSION_MAJOR; + res["versionMinor"] = ZEROTIER_ONE_VERSION_MINOR; + res["versionRev"] = ZEROTIER_ONE_VERSION_REVISION; + res["versionBuild"] = ZEROTIER_ONE_VERSION_BUILD; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%d.%d.%d",ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); + res["version"] = tmp; + res["clock"] = OSUtils::now(); + + { + Mutex::Lock _l(_localConfig_m); + res["config"] = _localConfig; + } + json &settings = res["config"]["settings"]; + settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; + + if (_multipathMode) { + json &multipathConfig = res["multipath"]; + ZT_PeerList *pl = _node->peers(); + char peerAddrStr[256]; + if (pl) { + for(unsigned long i=0;ipeerCount;++i) { + if (pl->peers[i].hadAggregateLink) { + nlohmann::json pj; + _peerAggregateLinkToJson(pj,&(pl->peers[i])); + OSUtils::ztsnprintf(peerAddrStr,sizeof(peerAddrStr),"%.10llx",pl->peers[i].address); + multipathConfig[peerAddrStr] = (pj); + } + } + } + } + + settings["portMappingEnabled"] = OSUtils::jsonBool(settings["portMappingEnabled"],true); + + scode = 200; + } else if (ps[0] == "network") { + ZT_VirtualNetworkList *nws = _node->networks(); + if (nws) { + if (ps.size() == 1) { + // Return [array] of all networks + + res = nlohmann::json::array(); + for(unsigned long i=0;inetworkCount;++i) { + OneService::NetworkSettings localSettings; + getNetworkSettings(nws->networks[i].nwid,localSettings); + nlohmann::json nj; + _networkToJson(nj,&(nws->networks[i]),portDeviceName(nws->networks[i].nwid),localSettings); + res.push_back(nj); + } + + scode = 200; + } else if (ps.size() == 2) { + // Return a single network by ID or 404 if not found + + const uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); + for(unsigned long i=0;inetworkCount;++i) { + if (nws->networks[i].nwid == wantnw) { + OneService::NetworkSettings localSettings; + getNetworkSettings(nws->networks[i].nwid,localSettings); + _networkToJson(res,&(nws->networks[i]),portDeviceName(nws->networks[i].nwid),localSettings); + scode = 200; + break; + } + } + + } else scode = 404; + _node->freeQueryResult((void *)nws); + } else scode = 500; + } else if (ps[0] == "peer") { + ZT_PeerList *pl = _node->peers(); + if (pl) { + if (ps.size() == 1) { + // Return [array] of all peers + + res = nlohmann::json::array(); + for(unsigned long i=0;ipeerCount;++i) { + nlohmann::json pj; + _peerToJson(pj,&(pl->peers[i])); + res.push_back(pj); + } + + scode = 200; + } else if (ps.size() == 2) { + // Return a single peer by ID or 404 if not found + + uint64_t wantp = Utils::hexStrToU64(ps[1].c_str()); + for(unsigned long i=0;ipeerCount;++i) { + if (pl->peers[i].address == wantp) { + _peerToJson(res,&(pl->peers[i])); + scode = 200; + break; + } + } + + } else scode = 404; + _node->freeQueryResult((void *)pl); + } else scode = 500; + } else { + if (_controller) { + scode = _controller->handleControlPlaneHttpGET(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType); + } else scode = 404; + } + + } else scode = 401; // isAuth == false + } else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) { + if (isAuth) { + + if (ps[0] == "network") { + if (ps.size() == 2) { + + uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); + _node->join(wantnw,(void *)0,(void *)0); // does nothing if we are a member + ZT_VirtualNetworkList *nws = _node->networks(); + if (nws) { + for(unsigned long i=0;inetworkCount;++i) { + if (nws->networks[i].nwid == wantnw) { + OneService::NetworkSettings localSettings; + getNetworkSettings(nws->networks[i].nwid,localSettings); + + try { + json j(OSUtils::jsonParse(body)); + if (j.is_object()) { + json &allowManaged = j["allowManaged"]; + if (allowManaged.is_boolean()) localSettings.allowManaged = (bool)allowManaged; + json &allowGlobal = j["allowGlobal"]; + if (allowGlobal.is_boolean()) localSettings.allowGlobal = (bool)allowGlobal; + json &allowDefault = j["allowDefault"]; + if (allowDefault.is_boolean()) localSettings.allowDefault = (bool)allowDefault; + } + } catch (std::exception &exc) { + } catch ( ... ) { + } + + setNetworkSettings(nws->networks[i].nwid,localSettings); + _networkToJson(res,&(nws->networks[i]),portDeviceName(nws->networks[i].nwid),localSettings); + + scode = 200; + break; + } + } + _node->freeQueryResult((void *)nws); + } else scode = 500; + + } else scode = 404; + } else { + if (_controller) + scode = _controller->handleControlPlaneHttpPOST(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType); + else scode = 404; + } + + } else scode = 401; // isAuth == false + } else if (httpMethod == HTTP_DELETE) { + if (isAuth) { + + if (ps[0] == "network") { + ZT_VirtualNetworkList *nws = _node->networks(); + if (nws) { + if (ps.size() == 2) { + uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); + for(unsigned long i=0;inetworkCount;++i) { + if (nws->networks[i].nwid == wantnw) { + _node->leave(wantnw,(void **)0,(void *)0); + res["result"] = true; + scode = 200; + break; + } + } + } // else 404 + _node->freeQueryResult((void *)nws); + } else scode = 500; + } else { + if (_controller) + scode = _controller->handleControlPlaneHttpDELETE(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType); + else scode = 404; + } + + } else scode = 401; // isAuth = false + } else { + scode = 400; + } + + if (responseBody.length() == 0) { + if ((res.is_object())||(res.is_array())) + responseBody = OSUtils::jsonDump(res); + else responseBody = "{}"; + responseContentType = "application/json"; + } + + // Wrap result in jsonp function call if the user included a jsonp= url argument. + // Also double-check isAuth since forbidding this without auth feels safer. + std::map::const_iterator jsonp(urlArgs.find("jsonp")); + if ((isAuth)&&(jsonp != urlArgs.end())&&(responseContentType == "application/json")) { + if (responseBody.length() > 0) + responseBody = jsonp->second + "(" + responseBody + ");"; + else responseBody = jsonp->second + "(null);"; + responseContentType = "application/javascript"; + } + + return scode; + } + + // Must be called after _localConfig is read or modified + void applyLocalConfig() + { + Mutex::Lock _l(_localConfig_m); + json lc(_localConfig); + + _v4Hints.clear(); + _v6Hints.clear(); + _v4Blacklists.clear(); + _v6Blacklists.clear(); + json &virt = lc["virtual"]; + if (virt.is_object()) { + for(json::iterator v(virt.begin());v!=virt.end();++v) { + const std::string nstr = v.key(); + if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { + const Address ztaddr(Utils::hexStrToU64(nstr.c_str())); + if (ztaddr) { + const uint64_t ztaddr2 = ztaddr.toInt(); + std::vector &v4h = _v4Hints[ztaddr2]; + std::vector &v6h = _v6Hints[ztaddr2]; + std::vector &v4b = _v4Blacklists[ztaddr2]; + std::vector &v6b = _v6Blacklists[ztaddr2]; + + json &tryAddrs = v.value()["try"]; + if (tryAddrs.is_array()) { + for(unsigned long i=0;i 0)) { + if (phy.value().is_object()) { + if (OSUtils::jsonBool(phy.value()["blacklist"],false)) { + if (net.ss_family == AF_INET) + _globalV4Blacklist.push_back(net); + else if (net.ss_family == AF_INET6) + _globalV6Blacklist.push_back(net); + } + } + } + } + } + + _allowManagementFrom.clear(); + _interfacePrefixBlacklist.clear(); + + json &settings = lc["settings"]; + + _primaryPort = (unsigned int)OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; + _allowSecondaryPort = OSUtils::jsonBool(settings["allowSecondaryPort"],true); + _secondaryPort = (unsigned int)OSUtils::jsonInt(settings["secondaryPort"],0); + _tertiaryPort = (unsigned int)OSUtils::jsonInt(settings["tertiaryPort"],0); + if (_secondaryPort != 0 || _tertiaryPort != 0) { + fprintf(stderr,"WARNING: using manually-specified ports. This can cause NAT issues." ZT_EOL_S); + } + _multipathMode = (unsigned int)OSUtils::jsonInt(settings["multipathMode"],0); + _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true); + + json &ignoreIfs = settings["interfacePrefixBlacklist"]; + if (ignoreIfs.is_array()) { + for(unsigned long i=0;i 0) + _interfacePrefixBlacklist.push_back(tmp); + } + } + + json &amf = settings["allowManagementFrom"]; + if (amf.is_array()) { + for(unsigned long i=0;i 0) { + bool allowed = false; + for (InetAddress addr : n.settings.allowManagedWhitelist) { + if (addr.containsAddress(target) && addr.netmaskBits() <= target.netmaskBits()) { + allowed = true; + break; + } + } + if (!allowed) return false; + } + + if (target.isDefaultRoute()) + return n.settings.allowDefault; + switch(target.ipScope()) { + case InetAddress::IP_SCOPE_NONE: + case InetAddress::IP_SCOPE_MULTICAST: + case InetAddress::IP_SCOPE_LOOPBACK: + case InetAddress::IP_SCOPE_LINK_LOCAL: + return false; + case InetAddress::IP_SCOPE_GLOBAL: + return n.settings.allowGlobal; + default: + return true; + } + } + + // Match only an IP from a vector of IPs -- used in syncManagedStuff() + bool matchIpOnly(const std::vector &ips,const InetAddress &ip) const + { + for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { + if (i->ipsEqual(ip)) + return true; + } + return false; + } + + // Apply or update managed IPs for a configured network (be sure n.tap exists) + void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes) + { + char ipbuf[64]; + + // assumes _nets_m is locked + if (syncIps) { + std::vector newManagedIps; + newManagedIps.reserve(n.config.assignedAddressCount); + for(unsigned int i=0;i(&(n.config.assignedAddresses[i])); + if (checkIfManagedIsAllowed(n,*ii)) + newManagedIps.push_back(*ii); + } + std::sort(newManagedIps.begin(),newManagedIps.end()); + newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end()); + + for(std::vector::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) { + if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) { + if (!n.tap->removeIp(*ip)) + fprintf(stderr,"ERROR: unable to remove ip address %s" ZT_EOL_S, ip->toString(ipbuf)); + } + } +#ifdef __SYNOLOGY__ + 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()) { + if (!n.tap->addIp(*ip)) + fprintf(stderr,"ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf)); + } + } +#endif + n.managedIps.swap(newManagedIps); + } + + if (syncRoutes) { + char tapdev[64]; +#if defined(__WINDOWS__) && !defined(ZT_SDK) + OSUtils::ztsnprintf(tapdev,sizeof(tapdev),"%.16llx",(unsigned long long)((WindowsEthernetTap *)(n.tap.get()))->luid().Value); +#else + Utils::scopy(tapdev,sizeof(tapdev),n.tap->deviceName().c_str()); +#endif + + std::vector myIps(n.tap->ips()); + + // Nuke applied routes that are no longer in n.config.routes[] and/or are not allowed + for(std::list< SharedPtr >::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();) { + bool haveRoute = false; + if ( (checkIfManagedIsAllowed(n,(*mr)->target())) && (((*mr)->via().ss_family != (*mr)->target().ss_family)||(!matchIpOnly(myIps,(*mr)->via()))) ) { + for(unsigned int i=0;i(&(n.config.routes[i].target)); + const InetAddress *const via = reinterpret_cast(&(n.config.routes[i].via)); + if ( ((*mr)->target() == *target) && ( ((via->ss_family == target->ss_family)&&((*mr)->via().ipsEqual(*via))) || (strcmp(tapdev,(*mr)->device())==0) ) ) { + haveRoute = true; + break; + } + } + } + if (haveRoute) { + ++mr; + } else { + n.managedRoutes.erase(mr++); + } + } + + // Apply routes in n.config.routes[] that we haven't applied yet, and sync those we have in case shadow routes need to change + for(unsigned int i=0;i(&(n.config.routes[i].target)); + const InetAddress *const via = reinterpret_cast(&(n.config.routes[i].via)); + + if ( (!checkIfManagedIsAllowed(n,*target)) || ((via->ss_family == target->ss_family)&&(matchIpOnly(myIps,*via))) ) + continue; + + bool haveRoute = false; + + // Ignore routes implied by local managed IPs since adding the IP adds the route +#ifndef __APPLE__ + for(std::vector::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) { + if ((target->netmaskBits() == ip->netmaskBits())&&(target->containsAddress(*ip))) { + haveRoute = true; + break; + } + } +#endif + if (haveRoute) + continue; +#ifndef ZT_SDK + // If we've already applied this route, just sync it and continue + for(std::list< SharedPtr >::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();++mr) { + if ( ((*mr)->target() == *target) && ( ((via->ss_family == target->ss_family)&&((*mr)->via().ipsEqual(*via))) || (tapdev == (*mr)->device()) ) ) { + haveRoute = true; + (*mr)->sync(); + break; + } + } + if (haveRoute) + continue; + + // Add and apply new routes + n.managedRoutes.push_back(SharedPtr(new ManagedRoute(*target,*via,tapdev))); + if (!n.managedRoutes.back()->sync()) + n.managedRoutes.pop_back(); +#endif + } + } + } + + // ========================================================================= + // Handlers for Node and Phy<> callbacks + // ========================================================================= + + inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) + { + const uint64_t now = OSUtils::now(); + if ((len >= 16)&&(reinterpret_cast(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) + _lastDirectReceiveFromGlobal = now; + const ZT_ResultCode rc = _node->processWirePacket(nullptr,now,reinterpret_cast(sock),reinterpret_cast(from),data,len,&_nextBackgroundTaskDeadline); + if (ZT_ResultCode_isFatal(rc)) { + char tmp[256]; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = tmp; + this->terminate(); + } + } + + inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) + { + _phy.close(sock,true); + } + + inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) + { + if (!from) { + _phy.close(sockN,false); + return; + } else { +#ifdef ZT_SDK + // Immediately close new local connections. The intention is to prevent the backplane from being accessed when operating as libzt + if (!allowHttpBackplaneManagement && ((InetAddress*)from)->ipScope() == InetAddress::IP_SCOPE_LOOPBACK) { + _phy.close(sockN,false); + return; + } +#endif + TcpConnection *tc = new TcpConnection(); + { + Mutex::Lock _l(_tcpConnections_m); + _tcpConnections.push_back(tc); + } + + tc->type = TcpConnection::TCP_UNCATEGORIZED_INCOMING; + tc->parent = this; + tc->sock = sockN; + tc->remoteAddr = from; + tc->lastReceive = OSUtils::now(); + http_parser_init(&(tc->parser),HTTP_REQUEST); + tc->parser.data = (void *)tc; + tc->messageSize = 0; + + *uptrN = (void *)tc; + } + } + + void phyOnTcpClose(PhySocket *sock,void **uptr) + { + TcpConnection *tc = (TcpConnection *)*uptr; + if (tc) { + { + Mutex::Lock _l(_tcpConnections_m); + _tcpConnections.erase(std::remove(_tcpConnections.begin(),_tcpConnections.end(),tc),_tcpConnections.end()); + } + delete tc; + } + } + + void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) + { + try { + if (!len) return; // sanity check, should never happen + TcpConnection *tc = reinterpret_cast(*uptr); + tc->lastReceive = OSUtils::now(); + switch(tc->type) { + + case TcpConnection::TCP_UNCATEGORIZED_INCOMING: + switch(reinterpret_cast(data)[0]) { + // HTTP: GET, PUT, POST, HEAD, DELETE + case 'G': + case 'P': + case 'D': + case 'H': { + // This is only allowed from IPs permitted to access the management + // backplane, which is just 127.0.0.1/::1 unless otherwise configured. + bool allow; + { + Mutex::Lock _l(_localConfig_m); + if (_allowManagementFrom.size() == 0) { + allow = (tc->remoteAddr.ipScope() == InetAddress::IP_SCOPE_LOOPBACK); + } else { + allow = false; + for(std::vector::const_iterator i(_allowManagementFrom.begin());i!=_allowManagementFrom.end();++i) { + if (i->containsAddress(tc->remoteAddr)) { + allow = true; + break; + } + } + } + } + if (allow) { + tc->type = TcpConnection::TCP_HTTP_INCOMING; + phyOnTcpData(sock,uptr,data,len); + } else { + _phy.close(sock); + } + } break; + + // Drop unknown protocols + default: + _phy.close(sock); + break; + } + return; + + case TcpConnection::TCP_HTTP_INCOMING: + http_parser_execute(&(tc->parser),&HTTP_PARSER_SETTINGS,(const char *)data,len); + if ((tc->parser.upgrade)||(tc->parser.http_errno != HPE_OK)) + _phy.close(sock); + return; + + } + } catch (std::exception &exc) { + _phy.close(sock); + } catch ( ... ) { + _phy.close(sock); + } + } + + inline void phyOnTcpWritable(PhySocket *sock,void **uptr) + { + TcpConnection *tc = reinterpret_cast(*uptr); + bool closeit = false; + { + Mutex::Lock _l(tc->writeq_m); + if (tc->writeq.length() > 0) { + long sent = (long)_phy.streamSend(sock,tc->writeq.data(),(unsigned long)tc->writeq.length(),true); + if (sent > 0) { + if ((unsigned long)sent >= (unsigned long)tc->writeq.length()) { + tc->writeq.clear(); + _phy.setNotifyWritable(sock,false); + + if (tc->type == TcpConnection::TCP_HTTP_INCOMING) + closeit = true; // HTTP keep alive not supported + } else { + tc->writeq.erase(tc->writeq.begin(),tc->writeq.begin() + sent); + } + } + } else { + _phy.setNotifyWritable(sock,false); + } + } + if (closeit) + _phy.close(sock); + } + + inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} + inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} + inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} + inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} + inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} + + inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc) + { + Mutex::Lock _l(_nets_m); + NetworkState &n = _nets[nwid]; + + switch(op) { + + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: + if (!n.tap) { + try { + char friendlyName[128]; + OSUtils::ztsnprintf(friendlyName,sizeof(friendlyName),"ZeroTier One [%.16llx]",nwid); + + n.tap = EthernetTap::newInstance( + nullptr, + _homePath.c_str(), + MAC(nwc->mac), + nwc->mtu, + (unsigned int)ZT_IF_METRIC, + nwid, + friendlyName, + StapFrameHandler, + (void *)this); + *nuptr = (void *)&n; + + char nlcpath[256]; + OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); + std::string nlcbuf; + if (OSUtils::readFile(nlcpath,nlcbuf)) { + Dictionary<4096> nc; + nc.load(nlcbuf.c_str()); + Buffer<1024> allowManaged; + if (nc.get("allowManaged", allowManaged) && allowManaged.size() != 0) { + std::string addresses (allowManaged.begin(), allowManaged.size()); + if (allowManaged.size() <= 5) { // untidy parsing for backward compatibility + if (allowManaged[0] == '1' || allowManaged[0] == 't' || allowManaged[0] == 'T') { + n.settings.allowManaged = true; + } else { + n.settings.allowManaged = false; + } + } else { + // this should be a list of IP addresses + n.settings.allowManaged = true; + size_t pos = 0; + while (true) { + size_t nextPos = addresses.find(',', pos); + std::string address = addresses.substr(pos, (nextPos == std::string::npos ? addresses.size() : nextPos) - pos); + n.settings.allowManagedWhitelist.push_back(InetAddress(address.c_str())); + if (nextPos == std::string::npos) break; + pos = nextPos + 1; + } + } + } else { + n.settings.allowManaged = true; + } + n.settings.allowGlobal = nc.getB("allowGlobal", false); + n.settings.allowDefault = nc.getB("allowDefault", false); + } + } catch (std::exception &exc) { +#ifdef __WINDOWS__ + FILE *tapFailLog = fopen((_homePath + ZT_PATH_SEPARATOR_S"port_error_log.txt").c_str(),"a"); + if (tapFailLog) { + fprintf(tapFailLog,"%.16llx: %s" ZT_EOL_S,(unsigned long long)nwid,exc.what()); + fclose(tapFailLog); + } +#else + fprintf(stderr,"ERROR: unable to configure virtual network port: %s" ZT_EOL_S,exc.what()); +#endif + _nets.erase(nwid); + return -999; + } catch (int exc) { + return -999; + } catch ( ... ) { + return -999; // tap init failed + } + } + // After setting up tap, fall through to CONFIG_UPDATE since we also want to do this... + + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: + memcpy(&(n.config),nwc,sizeof(ZT_VirtualNetworkConfig)); + if (n.tap) { // sanity check +#if defined(__WINDOWS__) && !defined(ZT_SDK) + // wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized + // + // without WindowsEthernetTap::isInitialized() returning true, the won't actually + // be online yet and setting managed routes on it will fail. + const int MAX_SLEEP_COUNT = 500; + for (int i = 0; !((WindowsEthernetTap *)(n.tap.get()))->isInitialized() && i < MAX_SLEEP_COUNT; i++) { + Sleep(10); + } +#endif + syncManagedStuff(n,true,true); + n.tap->setMtu(nwc->mtu); + } else { + _nets.erase(nwid); + return -999; // tap init failed + } + break; + + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: + if (n.tap) { // sanity check +#if defined(__WINDOWS__) && !defined(ZT_SDK) + std::string winInstanceId(((WindowsEthernetTap *)(n.tap.get()))->instanceId()); +#endif + *nuptr = (void *)0; + n.tap.reset(); + _nets.erase(nwid); +#if defined(__WINDOWS__) && !defined(ZT_SDK) + if ((op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY)&&(winInstanceId.length() > 0)) + WindowsEthernetTap::deletePersistentTapDevice(winInstanceId.c_str()); +#endif + if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) { + char nlcpath[256]; + OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); + OSUtils::rm(nlcpath); + } + } else { + _nets.erase(nwid); + } + break; + + } + return 0; + } + + inline void nodeEventCallback(enum ZT_Event event,const void *metaData) + { + switch(event) { + + case ZT_EVENT_TRACE: { + if (metaData) { + ::fprintf(stderr,"%s" ZT_EOL_S,(const char *)metaData); + ::fflush(stderr); + } + } break; + + case ZT_EVENT_REMOTE_TRACE: { + // TODO + } + + default: + break; + + } + } + + inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) + { + char p[1024]; + FILE *f; + bool secure = false; + char dirname[1024]; + dirname[0] = 0; + + switch(type) { + case ZT_STATE_OBJECT_IDENTITY_PUBLIC: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_IDENTITY_SECRET: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + secure = true; + break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); + secure = true; + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_ROOT_LIST: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "roots",_homePath.c_str()); + break; + default: + return; + } + + if ((len >= 0)&&(data)) { + // Check to see if we've already written this first. This reduces + // redundant writes and I/O overhead on most platforms and has + // little effect on others. + f = fopen(p,"rb"); + if (f) { + char *const buf = (char *)malloc(len*4); + if (buf) { + long l = (long)fread(buf,1,(size_t)(len*4),f); + fclose(f); + if ((l == (long)len)&&(memcmp(data,buf,l) == 0)) { + free(buf); + return; + } + free(buf); + } + } + + f = fopen(p,"wb"); + if ((!f)&&(dirname[0])) { // create subdirectory if it does not exist + OSUtils::mkdir(dirname); + f = fopen(p,"wb"); + } + if (f) { + if (fwrite(data,len,1,f) != 1) + fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); + fclose(f); + if (secure) + OSUtils::lockDownFile(p,false); + } else { + fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); + } + } else { + OSUtils::rm(p); + } + } + + inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) + { + char p[4096]; + switch(type) { + case ZT_STATE_OBJECT_IDENTITY_PUBLIC: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_IDENTITY_SECRET: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); + break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer",_homePath.c_str(),(unsigned long long)id[0]); + break; + default: + return -1; + } + FILE *f = fopen(p,"rb"); + if (f) { + int n = (int)fread(data,1,maxlen,f); + fclose(f); + if (n >= 0) + return n; + } + return -1; + } + + inline int nodeWirePacketSendFunction(const int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) + { + if ((localSocket != -1)&&(localSocket != 0)&&(_binder.isUdpSocketValid((PhySocket *)((uintptr_t)localSocket)))) { + if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),ttl); + const bool r = _phy.udpSend((PhySocket *)((uintptr_t)localSocket),(const struct sockaddr *)addr,data,len); + if ((ttl)&&(addr->ss_family == AF_INET)) _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),255); + return ((r) ? 0 : -1); + } else { + return ((_binder.udpSendAll(_phy,addr,data,len,ttl)) ? 0 : -1); + } + } + + inline void nodeVirtualNetworkFrameFunction(uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) + { + NetworkState *n = reinterpret_cast(*nuptr); + if ((!n)||(!n->tap)) + return; + n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); + } + + inline int nodePathCheckFunction(uint64_t ztaddr,const int64_t localSocket,const struct sockaddr_storage *remoteAddr) + { + // Make sure we're not trying to do ZeroTier-over-ZeroTier + { + Mutex::Lock _l(_nets_m); + for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { + if (n->second.tap) { + std::vector ips(n->second.tap->ips()); + for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { + if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { + return 0; + } + } + } + } + } + + /* Note: I do not think we need to scan for overlap with managed routes + * because of the "route forking" and interface binding that we do. This + * ensures (we hope) that ZeroTier traffic will still take the physical + * path even if its managed routes override this for other traffic. Will + * revisit if we see recursion problems. */ + + // Check blacklists + const Hashtable< uint64_t,std::vector > *blh = (const Hashtable< uint64_t,std::vector > *)0; + const std::vector *gbl = (const std::vector *)0; + if (remoteAddr->ss_family == AF_INET) { + blh = &_v4Blacklists; + gbl = &_globalV4Blacklist; + } else if (remoteAddr->ss_family == AF_INET6) { + blh = &_v6Blacklists; + gbl = &_globalV6Blacklist; + } + if (blh) { + Mutex::Lock _l(_localConfig_m); + const std::vector *l = blh->get(ztaddr); + if (l) { + for(std::vector::const_iterator a(l->begin());a!=l->end();++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + } + if (gbl) { + for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + return 1; + } + + inline int nodePathLookupFunction(uint64_t ztaddr,int family,struct sockaddr_storage *result) + { + const Hashtable< uint64_t,std::vector > *lh = (const Hashtable< uint64_t,std::vector > *)0; + if (family < 0) + lh = (Utils::random() & 1) ? &_v4Hints : &_v6Hints; + else if (family == AF_INET) + lh = &_v4Hints; + else if (family == AF_INET6) + lh = &_v6Hints; + else return 0; + const std::vector *l = lh->get(ztaddr); + if ((l)&&(l->size() > 0)) { + memcpy(result,&((*l)[(unsigned long)Utils::random() % l->size()]),sizeof(struct sockaddr_storage)); + return 1; + } else return 0; + } + + inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) + { + _node->processVirtualNetworkFrame((void *)0,OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); + } + + inline void onHttpRequestToServer(TcpConnection *tc) + { + char tmpn[4096]; + std::string data; + std::string contentType("text/plain"); // default if not changed in handleRequest() + unsigned int scode = 404; + + // Note that we check allowed IP ranges when HTTP connections are first detected in + // phyOnTcpData(). If we made it here the source IP is okay. + + try { + scode = handleControlPlaneHttpRequest(tc->remoteAddr,tc->parser.method,tc->url,tc->headers,tc->readq,data,contentType); + } catch (std::exception &exc) { + fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: %s" ZT_EOL_S,exc.what()); + scode = 500; + } catch ( ... ) { + fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: unknown exception" ZT_EOL_S); + scode = 500; + } + + const char *scodestr; + switch(scode) { + case 200: scodestr = "OK"; break; + case 400: scodestr = "Bad Request"; break; + case 401: scodestr = "Unauthorized"; break; + case 403: scodestr = "Forbidden"; break; + case 404: scodestr = "Not Found"; break; + case 500: scodestr = "Internal Server Error"; break; + case 501: scodestr = "Not Implemented"; break; + case 503: scodestr = "Service Unavailable"; break; + default: scodestr = "Error"; break; + } + + OSUtils::ztsnprintf(tmpn,sizeof(tmpn),"HTTP/1.1 %.3u %s\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nContent-Type: %s\r\nContent-Length: %lu\r\nConnection: close\r\n\r\n", + scode, + scodestr, + contentType.c_str(), + (unsigned long)data.length()); + { + Mutex::Lock _l(tc->writeq_m); + tc->writeq = tmpn; + if (tc->parser.method != HTTP_HEAD) + tc->writeq.append(data); + } + + _phy.setNotifyWritable(tc->sock,true); + } + + inline void onHttpResponseFromClient(TcpConnection *tc) + { + _phy.close(tc->sock); + } + + bool shouldBindInterface(const char *ifname,const InetAddress &ifaddr) + { +#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) + if ((ifname[0] == 'l')&&(ifname[1] == 'o')) return false; // loopback + if ((ifname[0] == 'z')&&(ifname[1] == 't')) return false; // sanity check: zt# + if ((ifname[0] == 't')&&(ifname[1] == 'u')&&(ifname[2] == 'n')) return false; // tun# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 't')&&(ifname[1] == 'a')&&(ifname[2] == 'p')) return false; // tap# is probably an OpenVPN tunnel or similar +#endif + +#ifdef __APPLE__ + if ((ifname[0] == 'f')&&(ifname[1] == 'e')&&(ifname[2] == 't')&&(ifname[3] == 'h')) return false; // ... as is feth# + if ((ifname[0] == 'l')&&(ifname[1] == 'o')) return false; // loopback + if ((ifname[0] == 'z')&&(ifname[1] == 't')) return false; // sanity check: zt# + if ((ifname[0] == 't')&&(ifname[1] == 'u')&&(ifname[2] == 'n')) return false; // tun# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 't')&&(ifname[1] == 'a')&&(ifname[2] == 'p')) return false; // tap# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 'u')&&(ifname[1] == 't')&&(ifname[2] == 'u')&&(ifname[3] == 'n')) return false; // ... as is utun# +#endif + + { + Mutex::Lock _l(_localConfig_m); + for(std::vector::const_iterator p(_interfacePrefixBlacklist.begin());p!=_interfacePrefixBlacklist.end();++p) { + if (!strncmp(p->c_str(),ifname,p->length())) + return false; + } + } + { + // Check global blacklists + const std::vector *gbl = (const std::vector *)0; + if (ifaddr.ss_family == AF_INET) { + gbl = &_globalV4Blacklist; + } else if (ifaddr.ss_family == AF_INET6) { + gbl = &_globalV6Blacklist; + } + if (gbl) { + Mutex::Lock _l(_localConfig_m); + for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { + if (a->containsAddress(ifaddr)) + return false; + } + } + } + { + Mutex::Lock _l(_nets_m); + for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { + if (n->second.tap) { + std::vector ips(n->second.tap->ips()); + for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { + if (i->ipsEqual(ifaddr)) + return false; + } + } + } + } + + return true; + } + + bool _trialBind(unsigned int port) + { + struct sockaddr_in in4; + struct sockaddr_in6 in6; + PhySocket *tb; + + memset(&in4,0,sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_port = Utils::hton((uint16_t)port); + tb = _phy.udpBind(reinterpret_cast(&in4),(void *)0,0); + if (tb) { + _phy.close(tb,false); + tb = _phy.tcpListen(reinterpret_cast(&in4),(void *)0); + if (tb) { + _phy.close(tb,false); + return true; + } + } + + memset(&in6,0,sizeof(in6)); + in6.sin6_family = AF_INET6; + in6.sin6_port = Utils::hton((uint16_t)port); + tb = _phy.udpBind(reinterpret_cast(&in6),(void *)0,0); + if (tb) { + _phy.close(tb,false); + tb = _phy.tcpListen(reinterpret_cast(&in6),(void *)0); + if (tb) { + _phy.close(tb,false); + return true; + } + } + + return false; + } +}; + +static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) +{ return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } +static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) +{ reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } +static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) +{ reinterpret_cast(uptr)->nodeStatePutFunction(type,id,data,len); } +static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) +{ return reinterpret_cast(uptr)->nodeStateGetFunction(type,id,data,maxlen); } +static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) +{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); } +static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +{ reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } +static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr) +{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); } +static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) +{ return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } +static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +{ reinterpret_cast(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } + +static int ShttpOnMessageBegin(http_parser *parser) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + tc->messageSize = 0; + tc->url.clear(); + tc->status.clear(); + tc->headers.clear(); + tc->readq.clear(); + return 0; +} +static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + tc->url.append(ptr,length); + return 0; +} +#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) +static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) +#else +static int ShttpOnStatus(http_parser *parser) +#endif +{ return 0; } +static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) { + tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + } + for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); + return 0; +} +static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + tc->currentHeaderValue.append(ptr,length); + return 0; +} +static int ShttpOnHeadersComplete(http_parser *parser) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) + tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; + return 0; +} +static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + tc->readq.append(ptr,length); + return 0; +} +static int ShttpOnMessageComplete(http_parser *parser) +{ + TcpConnection *tc = reinterpret_cast(parser->data); + if (tc->type == TcpConnection::TCP_HTTP_INCOMING) { + tc->parent->onHttpRequestToServer(tc); + } else { + tc->parent->onHttpResponseFromClient(tc); + } + return 0; +} + +} // anonymous namespace + +std::string OneService::platformDefaultHomePath() +{ + return OSUtils::platformDefaultHomePath(); +} + +OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); } +OneService::~OneService() {} + +} // namespace ZeroTier diff --git a/service/OneService.hpp b/attic/service/OneService.hpp similarity index 97% rename from service/OneService.hpp rename to attic/service/OneService.hpp index 3f8947ae..53bbe2b8 100644 --- a/service/OneService.hpp +++ b/attic/service/OneService.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -86,11 +86,6 @@ public: * Allow overriding of system default routes for "full tunnel" operation? */ bool allowDefault; - - /** - * Allow configuration of DNS for the network - */ - bool allowDNS; }; /** diff --git a/service/README.md b/attic/service/README.md similarity index 91% rename from service/README.md rename to attic/service/README.md index 94e920a5..c77ee511 100644 --- a/service/README.md +++ b/attic/service/README.md @@ -5,11 +5,7 @@ This is the actual implementation of ZeroTier One, a service providing connectiv ### Local Configuration File -A file called `local.conf` in the ZeroTier [home](https://github.com/zerotier/ZeroTierOne/blob/6faca86bb424d0b9643b6efa50571f73310d8276/README.md) folder contains configuration options that apply to the local node. (It does not exist unless you create it). It can be used to set up trusted paths, blacklist physical paths, set up physical path hints for certain nodes, and define trusted upstream devices (federated roots). In a large deployment it can be deployed using a tool like Puppet, Chef, SaltStack, etc. to set a uniform configuration across systems. - -It's a JSON format file that can also be edited and rewritten by ZeroTier One itself, so ensure that proper JSON formatting is used. To validate your config, paste it into a website like [jsonlint.com](https://jsonlint.com), or use a tool like `jq`. - -Check the output of `zerotier-cli info -j` to see if your configuration is being loaded. +A file called `local.conf` in the ZeroTier home folder contains configuration options that apply to the local node. (It does not exist unless you create it). It can be used to set up trusted paths, blacklist physical paths, set up physical path hints for certain nodes, and define trusted upstream devices (federated roots). In a large deployment it can be deployed using a tool like Puppet, Chef, SaltStack, etc. to set a uniform configuration across systems. It's a JSON format file that can also be edited and rewritten by ZeroTier One itself, so ensure that proper JSON formatting is used. Settings available in `local.conf` (this is not valid JSON, and JSON does not allow comments): @@ -33,7 +29,6 @@ Settings available in `local.conf` (this is not valid JSON, and JSON does not al "secondaryPort": 1-65535, /* If set, override default random secondary port */ "tertiaryPort": 1-65535, /* If set, override default random tertiary port */ "portMappingEnabled": true|false, /* If true (the default), try to use uPnP or NAT-PMP to map ports */ - "allowSecondaryPort": true|false /* false will also disable secondary port */ "softwareUpdate": "apply"|"download"|"disable", /* Automatically apply updates, just download, or disable built-in software updates */ "softwareUpdateChannel": "release"|"beta", /* Software update channel */ "softwareUpdateDist": true|false, /* If true, distribute software updates (only really useful to ZeroTier, Inc. itself, default is false) */ @@ -143,7 +138,6 @@ Most network settings are not writable, as they are defined by the network contr | allowManaged | boolean | Allow IP and route management | yes | | allowGlobal | boolean | Allow IPs and routes that overlap with global IPs | yes | | allowDefault | boolean | Allow overriding of system default route | yes | -| allowDNS | boolean | Allow configuration of DNS on network | yes | Route objects: diff --git a/update_controllers.sh b/attic/update_controllers.sh similarity index 100% rename from update_controllers.sh rename to attic/update_controllers.sh diff --git a/windows-clean.bat b/attic/windows-clean.bat similarity index 62% rename from windows-clean.bat rename to attic/windows-clean.bat index 96bc563a..09e5e28b 100644 --- a/windows-clean.bat +++ b/attic/windows-clean.bat @@ -1,12 +1,9 @@ DEL "ZeroTier One.msi" DEL zt1_update*.exe RMDIR /Q /S windows\Build -RMDIR /Q /S windows\x64 -RMDIR /Q /S windows\ARM64 -RMDIR /Q /S windows\Release RMDIR /Q /S windows\copyutil\bin RMDIR /Q /S windows\copyutil\obj +RMDIR /Q /S windows\WinUI\bin +RMDIR /Q /S windows\WinUI\obj RMDIR /Q /S windows\ZeroTierOne\Release RMDIR /Q /S windows\ZeroTierOne\x64 -RMDIR /Q /S zeroidc\x64 -RMDIR /Q /S zeroidc\target diff --git a/attic/world/README.md b/attic/world/README.md deleted file mode 100644 index dda4920a..00000000 --- a/attic/world/README.md +++ /dev/null @@ -1,7 +0,0 @@ -World Definitions and Generator Code -====== - -This little bit of code is used to generate world updates. Ordinary users probably will never need this unless they want to test or experiment. - -See mkworld.cpp for documentation. To build from this directory use 'source ./build.sh'. - diff --git a/attic/world/build.sh b/attic/world/build.sh deleted file mode 100755 index f3bcfabc..00000000 --- a/attic/world/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -c++ -std=c++11 -I../.. -I../../ext -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 deleted file mode 100644 index 6b9bbe8d..00000000 --- a/attic/world/mkworld.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 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 . - */ - -/* - * This utility makes the World from the configuration specified below. - * It probably won't be much use to anyone outside ZeroTier, Inc. except - * for testing and experimentation purposes. - * - * If you want to make your own World you must edit this file. - * - * When run, it expects two files in the current directory: - * - * previous.c25519 - key pair to sign this world (key from previous world) - * current.c25519 - key pair whose public key should be embedded in this world - * - * If these files do not exist, they are both created with the same key pair - * and a self-signed initial World is born. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace ZeroTier; - -int main(int argc,char **argv) -{ - std::string previous,current; - if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) { - C25519::Pair np(C25519::generate()); - previous = std::string(); - previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN); - previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN); - current = previous; - OSUtils::writeFile("previous.c25519",previous); - OSUtils::writeFile("current.c25519",current); - fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)" ZT_EOL_S); - } - - if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) { - fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S); - return 1; - } - C25519::Pair previousKP; - memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN); - memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); - C25519::Pair currentKP; - memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN); - memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); - - // ========================================================================= - // EDIT BELOW HERE - - std::vector roots; - - const uint64_t id = ZT_WORLD_ID_EARTH; - 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")); - - // Miami - roots.push_back(World::Root()); - 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 - - // END WORLD DEFINITION - // ========================================================================= - - fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu" ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts); - - World nw = World::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP); - - Buffer outtmp; - nw.serialize(outtmp,false); - World testw; - testw.deserialize(outtmp,0); - if (testw != nw) { - fprintf(stderr,"FATAL: serialization test failed!" ZT_EOL_S); - return 1; - } - - OSUtils::writeFile("world.bin",std::string((const char *)outtmp.data(),outtmp.size())); - fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data." ZT_EOL_S,outtmp.size()); - - fprintf(stdout,ZT_EOL_S); - fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u" ZT_EOL_S,outtmp.size()); - fprintf(stdout,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {"); - for(unsigned int i=0;i 0) - fprintf(stdout,","); - fprintf(stdout,"0x%.2x",(unsigned int)d[i]); - } - fprintf(stdout,"};" ZT_EOL_S); - - return 0; -} diff --git a/attic/world/world.bin b/attic/world/world.bin deleted file mode 100644 index 88049ccd..00000000 Binary files a/attic/world/world.bin and /dev/null differ diff --git a/attic/world/world.c b/attic/world/world.c deleted file mode 100644 index ecf30e6f..00000000 --- a/attic/world/world.c +++ /dev/null @@ -1,3 +0,0 @@ - -#define ZT_DEFAULT_WORLD_LENGTH 732 -static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x6b,0xd4,0x16,0x08,0xc1,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,0x16,0x93,0xf4,0xe5,0xbd,0x20,0xda,0x10,0xad,0xc7,0x05,0xf4,0x99,0xfe,0x04,0x08,0x9b,0xe0,0x9e,0x77,0x1d,0x9f,0x47,0x16,0xaa,0x92,0x4f,0x10,0x16,0x3d,0xc7,0xec,0xd3,0x90,0x9e,0xd1,0x74,0xfc,0xb3,0xb5,0x07,0x9c,0x4d,0x95,0xc5,0x17,0x8b,0x3d,0x0b,0x60,0x76,0xe8,0x51,0xbb,0xb6,0x3d,0x74,0xb5,0x21,0x83,0x7b,0x95,0x1d,0x02,0x9b,0xcd,0xaf,0x5c,0x3e,0x96,0xdf,0x37,0x2c,0x56,0x6d,0xfa,0x75,0x0f,0xda,0x55,0x85,0x13,0xf4,0x76,0x1a,0x66,0x4d,0x3b,0x8d,0xcf,0x12,0xc9,0x34,0xb9,0x0d,0x61,0x03,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,0x02,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,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,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0x83,0xff,0x06,0x10,0x27,0x09,0x06,0x28,0x03,0xeb,0x80,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,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,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,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,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09}; diff --git a/ci/Dockerfile-build.deb b/ci/Dockerfile-build.deb deleted file mode 100644 index 09ed717f..00000000 --- a/ci/Dockerfile-build.deb +++ /dev/null @@ -1,13 +0,0 @@ -ARG ZT_NAME -FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-builder as builder -WORKDIR /work/build -COPY . . -RUN pwd -RUN ls -la . -RUN make clean -RUN make debian -RUN ls -ls /work - -FROM scratch AS export -ARG ZT_NAME -COPY --from=builder /work/*.deb ./${ZT_NAME}/ diff --git a/ci/Dockerfile-build.el6 b/ci/Dockerfile-build.el6 deleted file mode 100644 index c5848c98..00000000 --- a/ci/Dockerfile-build.el6 +++ /dev/null @@ -1,36 +0,0 @@ -ARG DOCKER_ARCH -FROM --platform=linux/${DOCKER_ARCH} alpine:edge AS builder - -RUN apk update -RUN apk add curl -RUN apk add bash -RUN apk add file -RUN apk add rust -RUN apk add cargo -RUN apk add make -RUN apk add cmake -RUN apk add clang -RUN apk add openssl-dev -RUN apk add linux-headers -RUN apk add build-base -RUN apk add openssl-libs-static - -COPY . . -RUN ZT_STATIC=1 make -RUN ls -la - -ARG DOCKER_ARCH -FROM --platform=linux/${DOCKER_ARCH} centos:6 AS stage -WORKDIR /root/rpmbuild/BUILD -COPY . . -COPY --from=builder zerotier-* ./ -RUN curl https://gist.githubusercontent.com/someara/b363002ba6e57b3c474dd027d4daef85/raw/4ac5534139752fc92fbe1a53599a390214f69615/el6%2520vault --output /etc/yum.repos.d/CentOS-Base.repo -RUN uname -a -RUN yum -y install make gcc rpm-build -RUN pwd -RUN ls -la -RUN make redhat - -FROM scratch AS export -ARG ZT_NAME -COPY --from=stage /root/rpmbuild/RPMS/*/*.rpm ./${ZT_NAME}/ diff --git a/ci/Dockerfile-build.rpm b/ci/Dockerfile-build.rpm deleted file mode 100644 index cab00a06..00000000 --- a/ci/Dockerfile-build.rpm +++ /dev/null @@ -1,9 +0,0 @@ -ARG ZT_NAME -FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-builder as builder -WORKDIR /root/rpmbuild/BUILD -COPY . . -RUN make redhat - -FROM scratch AS export -ARG ZT_NAME -COPY --from=builder /root/rpmbuild/RPMS/*/*.rpm ./${ZT_NAME}/ diff --git a/ci/Dockerfile-test.deb b/ci/Dockerfile-test.deb deleted file mode 100644 index 7c709a86..00000000 --- a/ci/Dockerfile-test.deb +++ /dev/null @@ -1,13 +0,0 @@ -ARG ZT_NAME -FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-tester -ARG BASEURL -ARG VERSION -ARG DEB_ARCH -ARG ZT_NAME -ARG DISTRO -RUN curl -s http://${BASEURL}/key.gpg -o /etc/apt/trusted.gpg.d/zerotier.gpg -RUN echo "deb [arch=${DEB_ARCH} signed-by=/etc/apt/trusted.gpg.d/zerotier.gpg] http://${BASEURL}/${DISTRO} ${ZT_NAME} main" > /etc/apt/sources.list.d/zerotier.list -RUN apt-get -qq update -RUN apt-get -qq install zerotier-one=${VERSION} - -RUN ldd $(which zerotier-cli) diff --git a/ci/Dockerfile-test.el6 b/ci/Dockerfile-test.el6 deleted file mode 100644 index 49966731..00000000 --- a/ci/Dockerfile-test.el6 +++ /dev/null @@ -1,4 +0,0 @@ -ARG DOCKER_ARCH -FROM --platform=linux/${DOCKER_ARCH} centos:6 -RUN printf "[C6.10-base]\nname=CentOS-6.10 - Base\nbaseurl=http://vault.epel.cloud/6.10/os/\$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6\nenabled=1\nmetadata_expire=never\n" > /etc/yum.repos.d/CentOS-Base.repo -RUN yum -y install curl diff --git a/ci/Dockerfile-test.rpm b/ci/Dockerfile-test.rpm deleted file mode 100644 index 6a98607b..00000000 --- a/ci/Dockerfile-test.rpm +++ /dev/null @@ -1,17 +0,0 @@ -ARG ZT_NAME -FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-tester -ARG BASEURL -ARG VERSION -ARG DEB_ARCH -ARG ZT_NAME -ARG DISTRO -ARG DNF_ARCH -RUN curl -s http://${BASEURL}/key.asc -o /etc/pki/rpm-gpg/RPM-GPG-KEY-zerotier -RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-zerotier -RUN rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' -RUN printf "[zerotier]\nname=zerotier\nbaseurl=http://${BASEURL}/${DISTRO}/${ZT_NAME}/$basearch/\nenabled=1\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-zerotier\n" > /etc/yum.repos.d/zerotier.repo - -# RUN yum -v repolist -RUN setarch ${DNF_ARCH} yum -y install zerotier-one-${VERSION} -RUN file $(which zerotier-cli) -RUN ldd $(which zerotier-cli) diff --git a/ci/scripts/build.sh b/ci/scripts/build.sh deleted file mode 100755 index a4b8ca94..00000000 --- a/ci/scripts/build.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -set -euo pipefail -IFS=$'\n\t' - -ZT_NAME="$1" ; shift -DISTRO="$1" ; shift -ZT_ISA="$1" ; shift -VERSION="$1" ; shift -BUILD_EVENT="$1" ; shift - -source "$(dirname $0)/lib.sh" - -if [ -f "ci/Dockerfile-build.${ZT_NAME}" ]; then - DOCKERFILE="ci/Dockerfile-build.${ZT_NAME}" -else - DOCKERFILE="ci/Dockerfile-build.${PKGFMT}" -fi - -echo "#~~~~~~~~~~~~~~~~~~~~" -echo "$0 variables:" -echo "nproc: $(nproc)" -echo "ZT_NAME: ${ZT_NAME}" -echo "DISTRO: ${DISTRO}" -echo "ZT_ISA: ${ZT_ISA}" -echo "VERSION: ${VERSION}" -echo "BUILD_EVENT: ${BUILD_EVENT}" -echo "DOCKER_ARCH: ${DOCKER_ARCH}" -echo "DNF_ARCH: ${DNF_ARCH}" -echo "RUST_TRIPLET: ${RUST_TRIPLET}" -echo "PKGFMT: ${PKGFMT}" -echo "PWD: ${PWD}" -echo "DOCKERFILE: ${DOCKERFILE}" -echo "#~~~~~~~~~~~~~~~~~~~~" - -make munge_rpm zerotier-one.spec VERSION=${VERSION} -make munge_deb debian/changelog VERSION=${VERSION} - -docker buildx build \ - --no-cache=true \ - --build-arg ZT_NAME="${ZT_NAME}" \ - --build-arg RUST_TRIPLET="${RUST_TRIPLET}" \ - --build-arg DOCKER_ARCH="${DOCKER_ARCH}" \ - --build-arg DNF_ARCH="${DNF_ARCH}" \ - --platform linux/${DOCKER_ARCH} \ - -f ${DOCKERFILE} \ - -t build \ - . \ - --output type=local,dest=. \ - --target export diff --git a/ci/scripts/lib.sh b/ci/scripts/lib.sh deleted file mode 100755 index 43c35762..00000000 --- a/ci/scripts/lib.sh +++ /dev/null @@ -1,63 +0,0 @@ - -case $ZT_NAME in - el*|fc*|amzn*) - export PKGFMT=rpm - ;; - *) - export PKGFMT=deb -esac - -case $ZT_ISA in - 386) - export DOCKER_ARCH=386 - export DEB_ARCH=i386 - export DNF_ARCH=i686 - export RUST_TRIPLET=i686-unknown-linux-gnu - ;; - amd64) - export DOCKER_ARCH=amd64 - export DEB_ARCH=amd64 - export DNF_ARCH=x86_64 - export RUST_TRIPLET=x86_64-unknown-linux-gnu - ;; - armv7) - export DOCKER_ARCH=arm/v7 - export DNF_ARCH=armv7 - export DEB_ARCH=armhf - export RUST_TRIPLET=armv7-unknown-linux-gnueabihf - ;; - arm64) - export DOCKER_ARCH=arm64/v8 - export DEB_ARCH=arm64 - export DNF_ARCH=linux64 - export RUST_TRIPLET=aarch64-unknown-linux-gnu - ;; - riscv64) - export DOCKER_ARCH=riscv64 - export DEB_ARCH=riscv64 - export DNF_ARCH=riscv64 - export RUST_TRIPLET=riscv64gc-unknown-linux-gnu - ;; - ppc64le) - export DOCKER_ARCH=ppc64le - export DEB_ARCH=ppc64el - export DNF_ARCH=ppc64le - export RUST_TRIPLET=powerpc64le-unknown-linux-gnu - ;; - mips64le) - export DOCKER_ARCH=mips64le - export DEB_ARCH=mips64le - export DNF_ARCH=mips64le - export RUST_TRIPLET=mips64el-unknown-linux-gnuabi64 - ;; - s390x) - export DOCKER_ARCH=s390x - export DEB_ARCH=s390x - export DNF_ARCH=s390x - export RUST_TRIPLET=s390x-unknown-linux-gnu - ;; - *) - echo "ERROR: could not determine architecture settings. PLEASE FIX ME" - exit 1 - ;; -esac diff --git a/ci/scripts/munge_debian_changelog.sh b/ci/scripts/munge_debian_changelog.sh deleted file mode 100755 index d37cb063..00000000 --- a/ci/scripts/munge_debian_changelog.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -set -euo pipefail -IFS=$'\n\t' - -export FILE=$1 -export VERSION=$2 -export NAME=$3 -export MESSAGE=$4 -export DATE=$(date "+%a, %d %b %Y %T %z") -# export DATE=$(date "+%a %b %d %Y") - -set +e -grep --version | grep BSD &> /dev/null -if [ $? == 0 ]; then BSDGREP=true ; else BSDGREP=false ; fi -set -e - -# echo "#~~~~~~~~~~~~~~~~~~~~" -# echo "$0 variables:" -# echo "VERSION: ${VERSION}" -# echo "NAME: ${NAME}" -# echo "MESSAGE: ${MESSAGE}" -# echo "DATE: ${DATE}" -# echo "BSDGREP: ${BSDGREP}" -# echo "#~~~~~~~~~~~~~~~~~~~~" -# echo - -if $BSDGREP ; then - sed -i '' s/^Version:.*/"Version: ${VERSION}"/ ${FILE} -else - sed -i s/^Version:.*/"Version: ${VERSION}"/ ${FILE} -fi - -awk -v version=${VERSION} -v date=${DATE} -v name=${NAME} -v message=${MESSAGE} \ - 'BEGIN{print "zerotier-one (" version ") stable; urgency=medium\n\n * " message "\n\n -- " name " " date "\n" }{ print }' \ - ${FILE} > ${FILE}.new - -mv ${FILE}.new ${FILE} diff --git a/ci/scripts/munge_rpm_spec.sh b/ci/scripts/munge_rpm_spec.sh deleted file mode 100755 index 289df1ed..00000000 --- a/ci/scripts/munge_rpm_spec.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -set -euo pipefail -IFS=$'\n\t' - -export FILE=$1 -export VERSION=$2 -export NAME=$3 -export MESSAGE=$4 -export DATE=$(date "+%a %b %d %Y") - -set +e -grep --version | grep BSD &> /dev/null -if [ $? == 0 ]; then BSDGREP=true ; else BSDGREP=false ; fi -set -e - -# echo "#~~~~~~~~~~~~~~~~~~~~" -# echo "$0 variables:" -# echo "VERSION: ${VERSION}" -# echo "NAME: ${NAME}" -# echo "MESSAGE: ${MESSAGE}" -# echo "DATE: ${DATE}" -# echo "BSDGREP: ${BSDGREP}" -# echo "#~~~~~~~~~~~~~~~~~~~~" -# echo - -if $BSDGREP ; then - sed -i '' s/^Version:.*/"Version: ${VERSION}"/ ${FILE} -else - sed -i s/^Version:.*/"Version: ${VERSION}"/ ${FILE} -fi - -awk -v version=${VERSION} -v date=${DATE} -v name=${NAME} -v message=${MESSAGE} \ - 'FNR==NR{ if (/%changelog/) p=NR; next} 1; FNR==p{ print "* " date " " name " - " version "\n- " message "\n" }' \ - ${FILE} ${FILE} > ${FILE}.new - -mv ${FILE}.new ${FILE} diff --git a/ci/scripts/publish.sh b/ci/scripts/publish.sh deleted file mode 100755 index fa1e2468..00000000 --- a/ci/scripts/publish.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -set -euo pipefail -IFS=$'\n\t' - -ZT_NAME="$1" ; shift -DISTRO="$1" ; shift -ZT_ISA="$1" ; shift -VERSION="$1" ; shift -BUILD_EVENT="$1" ; shift - -source "$(dirname $0)/lib.sh" - -if [ ${BUILD_EVENT} == "tag" ]; then - CHANNEL="zerotier-releases" -else - CHANNEL="zerotier-builds" -fi - -function publish_rpm { - mkdir -p /${CHANNEL}/${DISTRO} - ls -la /${CHANNEL} - ls -la . - cp -a ${ZT_NAME} /${CHANNEL}/${DISTRO} -} - -function publish_deb { - mkdir -p /${CHANNEL}/${DISTRO}/pool/dists/${ZT_NAME}/main - cp -a ${ZT_NAME}/* /${CHANNEL}/${DISTRO}/pool/dists/${ZT_NAME}/main -} - -case ${PKGFMT} in - "rpm") - publish_rpm - ;; - "deb") - publish_deb -esac - diff --git a/ci/scripts/test.sh b/ci/scripts/test.sh deleted file mode 100755 index 931e9bb9..00000000 --- a/ci/scripts/test.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -set -euo pipefail -IFS=$'\n\t' - -ZT_NAME="$1" ; shift -DISTRO="$1" ; shift -ZT_ISA="$1" ; shift -VERSION="$1" ; shift -BUILD_EVENT="$1" ; shift - -source "$(dirname $0)/lib.sh" - -if [ -f "ci/Dockerfile-test.${ZT_NAME}" ]; then - DOCKERFILE="ci/Dockerfile-test.${ZT_NAME}" -else - DOCKERFILE="ci/Dockerfile-test.${PKGFMT}" -fi - -if [ ${BUILD_EVENT} == "tag" ]; then - BASEURL="zerotier-releases.home.arpa" -else - BASEURL="zerotier-builds.home.arpa" -fi - -echo "#~~~~~~~~~~~~~~~~~~~~" -echo "$0 variables:" -echo "nproc: $(nproc)" -echo "ZT_NAME: ${ZT_NAME}" -echo "DISTRO: ${DISTRO}" -echo "ZT_ISA: ${ZT_ISA}" -echo "VERSION: ${VERSION}" -echo "BUILD_EVENT: ${BUILD_EVENT}" -echo "DOCKER_ARCH: ${DOCKER_ARCH}" -echo "DNF_ARCH: ${DNF_ARCH}" -echo "RUST_TRIPLET: ${RUST_TRIPLET}" -echo "PKGFMT: ${PKGFMT}" -echo "PWD: ${PWD}" -echo "DOCKERFILE: ${DOCKERFILE}" -echo "#~~~~~~~~~~~~~~~~~~~~" - -# docker pull -q --platform="linux/${DOCKER_ARCH}" 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-tester - -docker buildx build \ - --build-arg BASEURL="${BASEURL}" \ - --build-arg ZT_NAME="${ZT_NAME}" \ - --build-arg DISTRO="${DISTRO}" \ - --build-arg DEB_ARCH="${DEB_ARCH}" \ - --build-arg DNF_ARCH="${DNF_ARCH}" \ - --build-arg VERSION="${VERSION}" \ - --build-arg DOCKER_ARCH="${DOCKER_ARCH}" \ - --platform "linux/${DOCKER_ARCH}" \ - --no-cache \ - -f ${DOCKERFILE} \ - -t test \ - . diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt new file mode 100644 index 00000000..c886b54b --- /dev/null +++ b/controller/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8) +project(zt_controller) + +if(WIN32) + add_definitions(-DNOMINMAX) +endif(WIN32) + +set(ctl_src + DB.cpp + DBMirrorSet.cpp + EmbeddedNetworkController.cpp + FileDB.cpp + LFDB.cpp + RabbitMQ.cpp +) + +set(ctl_hdr + DB.hpp + DBMirrorSet.hpp + EmbeddedNetworkController.hpp + FileDB.hpp + LFDB.hpp + RabbitMQ.hpp +) + +if(BUILD_CENTRAL_CONTROLLER) + add_definitions(-DZT_CONTROLLER_USE_LIBPQ) + include_directories("../ext/librabbitmq/librabbitmq" ${PostgreSQL_INCLUDE_DIRS}) + + set(ctl_src ${ctl_src} PostgreSQL.cpp) + set(ctl_hdr ${ctl_hdr} PostgreSQL.hpp) +endif(BUILD_CENTRAL_CONTROLLER) + +add_library(${PROJECT_NAME} STATIC ${ctl_src} ${ctl_hdr}) +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) + diff --git a/controller/ConnectionPool.hpp b/controller/ConnectionPool.hpp deleted file mode 100644 index 8ccfb6be..00000000 --- a/controller/ConnectionPool.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c)2021 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: 2026-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. - */ -/****/ - -#ifndef ZT_CONNECTION_POOL_H_ -#define ZT_CONNECTION_POOL_H_ - - -#ifndef _DEBUG - #define _DEBUG(x) -#endif - -#include "../node/Metrics.hpp" - -#include -#include -#include -#include -#include -#include - -namespace ZeroTier { - -struct ConnectionUnavailable : std::exception { - char const* what() const throw() { - return "Unable to allocate connection"; - }; -}; - - -class Connection { -public: - virtual ~Connection() {}; -}; - -class ConnectionFactory { -public: - virtual ~ConnectionFactory() {}; - virtual std::shared_ptr create()=0; -}; - -struct ConnectionPoolStats { - size_t pool_size; - size_t borrowed_size; -}; - -template -class ConnectionPool { -public: - ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr factory) - : m_maxPoolSize(max_pool_size) - , m_minPoolSize(min_pool_size) - , m_factory(factory) - { - Metrics::max_pool_size += max_pool_size; - Metrics::min_pool_size += min_pool_size; - while(m_pool.size() < m_minPoolSize){ - m_pool.push_back(m_factory->create()); - Metrics::pool_avail++; - } - }; - - ConnectionPoolStats get_stats() { - std::unique_lock lock(m_poolMutex); - - ConnectionPoolStats stats; - stats.pool_size = m_pool.size(); - stats.borrowed_size = m_borrowed.size(); - - return stats; - }; - - ~ConnectionPool() { - }; - - /** - * Borrow - * - * Borrow a connection for temporary use - * - * When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope. This will cause it to automatically be replaced. - * @retval a shared_ptr to the connection object - */ - std::shared_ptr borrow() { - std::unique_lock l(m_poolMutex); - - while((m_pool.size() + m_borrowed.size()) < m_minPoolSize) { - std::shared_ptr conn = m_factory->create(); - m_pool.push_back(conn); - Metrics::pool_avail++; - } - - if(m_pool.size()==0){ - - if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) { - try { - std::shared_ptr conn = m_factory->create(); - m_borrowed.insert(conn); - Metrics::pool_in_use++; - return std::static_pointer_cast(conn); - } catch (std::exception &e) { - Metrics::pool_errors++; - throw ConnectionUnavailable(); - } - } else { - for(auto it = m_borrowed.begin(); it != m_borrowed.end(); ++it){ - if((*it).unique()) { - // This connection has been abandoned! Destroy it and create a new connection - try { - // If we are able to create a new connection, return it - _DEBUG("Creating new connection to replace discarded connection"); - std::shared_ptr conn = m_factory->create(); - m_borrowed.erase(it); - m_borrowed.insert(conn); - return std::static_pointer_cast(conn); - } catch(std::exception& e) { - // Error creating a replacement connection - Metrics::pool_errors++; - throw ConnectionUnavailable(); - } - } - } - // Nothing available - Metrics::pool_errors++; - throw ConnectionUnavailable(); - } - } - - // Take one off the front - std::shared_ptr conn = m_pool.front(); - m_pool.pop_front(); - Metrics::pool_avail--; - // Add it to the borrowed list - m_borrowed.insert(conn); - Metrics::pool_in_use++; - return std::static_pointer_cast(conn); - }; - - /** - * Unborrow a connection - * - * Only call this if you are returning a working connection. If the connection was bad, just let it go out of scope (so the connection manager can replace it). - * @param the connection - */ - void unborrow(std::shared_ptr conn) { - // Lock - std::unique_lock lock(m_poolMutex); - m_borrowed.erase(conn); - Metrics::pool_in_use--; - if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) { - Metrics::pool_avail++; - m_pool.push_back(conn); - } - }; -protected: - size_t m_maxPoolSize; - size_t m_minPoolSize; - std::shared_ptr m_factory; - std::deque > m_pool; - std::set > m_borrowed; - std::mutex m_poolMutex; -}; - -} - -#endif diff --git a/controller/DB.cpp b/controller/DB.cpp index 2c354ae7..dfa4fa09 100644 --- a/controller/DB.cpp +++ b/controller/DB.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -13,7 +13,6 @@ #include "DB.hpp" #include "EmbeddedNetworkController.hpp" -#include "../node/Metrics.hpp" #include #include @@ -49,18 +48,12 @@ void DB::initNetwork(nlohmann::json &network) { "type","ACTION_ACCEPT" } }}; } - if (!network.count("dns")) network["dns"] = nlohmann::json::array(); - if (!network.count("ssoEnabled")) network["ssoEnabled"] = false; - if (!network.count("clientId")) network["clientId"] = ""; - if (!network.count("authorizationEndpoint")) network["authorizationEndpoint"] = ""; - network["objtype"] = "network"; } void DB::initMember(nlohmann::json &member) { if (!member.count("authorized")) member["authorized"] = false; - if (!member.count("ssoExempt")) member["ssoExempt"] = false; if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array(); if (!member.count("activeBridge")) member["activeBridge"] = false; if (!member.count("tags")) member["tags"] = nlohmann::json::array(); @@ -72,7 +65,6 @@ void DB::initMember(nlohmann::json &member) if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL; if (!member.count("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json(); if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json(); - if (!member.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = 0LL; if (!member.count("vMajor")) member["vMajor"] = -1; if (!member.count("vMinor")) member["vMinor"] = -1; if (!member.count("vRev")) member["vRev"] = -1; @@ -98,8 +90,6 @@ void DB::cleanMember(nlohmann::json &member) member.erase("recentLog"); member.erase("lastModified"); member.erase("lastRequestMetaData"); - member.erase("authenticationURL"); // computed - member.erase("authenticationClientID"); // computed } DB::DB() {} @@ -108,17 +98,16 @@ DB::~DB() {} bool DB::get(const uint64_t networkId,nlohmann::json &network) { waitForReady(); - Metrics::db_get_network++; std::shared_ptr<_Network> nw; { - std::shared_lock l(_networks_l); + std::lock_guard l(_networks_l); auto nwi = _networks.find(networkId); if (nwi == _networks.end()) return false; nw = nwi->second; } { - std::shared_lock l2(nw->lock); + std::lock_guard l2(nw->lock); network = nw->config; } return true; @@ -127,17 +116,16 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network) bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member) { waitForReady(); - Metrics::db_get_network_and_member++; std::shared_ptr<_Network> nw; { - std::shared_lock l(_networks_l); + std::lock_guard l(_networks_l); auto nwi = _networks.find(networkId); if (nwi == _networks.end()) return false; nw = nwi->second; } { - std::shared_lock l2(nw->lock); + std::lock_guard l2(nw->lock); network = nw->config; auto m = nw->members.find(memberId); if (m == nw->members.end()) @@ -150,17 +138,16 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info) { waitForReady(); - Metrics::db_get_network_and_member_and_summary++; std::shared_ptr<_Network> nw; { - std::shared_lock l(_networks_l); + std::lock_guard l(_networks_l); auto nwi = _networks.find(networkId); if (nwi == _networks.end()) return false; nw = nwi->second; } { - std::shared_lock l2(nw->lock); + std::lock_guard l2(nw->lock); network = nw->config; _fillSummaryInfo(nw,info); auto m = nw->members.find(memberId); @@ -174,21 +161,19 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector &members) { waitForReady(); - Metrics::db_get_member_list++; std::shared_ptr<_Network> nw; { - std::shared_lock l(_networks_l); + std::lock_guard l(_networks_l); auto nwi = _networks.find(networkId); if (nwi == _networks.end()) return false; nw = nwi->second; } { - std::shared_lock l2(nw->lock); + std::lock_guard l2(nw->lock); network = nw->config; - for(auto m=nw->members.begin();m!=nw->members.end();++m) { + for(auto m=nw->members.begin();m!=nw->members.end();++m) members.push_back(m->second); - } } return true; } @@ -196,15 +181,13 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector &networks) { waitForReady(); - Metrics::db_get_network_list++; - std::shared_lock l(_networks_l); + std::lock_guard l(_networks_l); for(auto n=_networks.begin();n!=_networks.end();++n) networks.insert(n->first); } void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) { - Metrics::db_member_change++; uint64_t memberId = 0; uint64_t networkId = 0; bool isAuth = false; @@ -216,21 +199,18 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no networkId = OSUtils::jsonIntHex(old["nwid"],0ULL); if ((memberId)&&(networkId)) { { - std::unique_lock l(_networks_l); + std::lock_guard l(_networks_l); auto nw2 = _networks.find(networkId); - if (nw2 != _networks.end()) { + if (nw2 != _networks.end()) nw = nw2->second; - } } if (nw) { - std::unique_lock l(nw->lock); - if (OSUtils::jsonBool(old["activeBridge"],false)) { + std::lock_guard l(nw->lock); + if (OSUtils::jsonBool(old["activeBridge"],false)) nw->activeBridgeMembers.erase(memberId); - } wasAuth = OSUtils::jsonBool(old["authorized"],false); - if (wasAuth) { + if (wasAuth) nw->authorizedMembers.erase(memberId); - } json &ips = old["ipAssignments"]; if (ips.is_array()) { for(unsigned long i=0;i l(_networks_l); + std::lock_guard l(_networks_l); std::shared_ptr<_Network> &nw2 = _networks[networkId]; if (!nw2) nw2.reset(new _Network); @@ -261,18 +241,15 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no } { - std::unique_lock l(nw->lock); + std::lock_guard l(nw->lock); nw->members[memberId] = memberConfig; - if (OSUtils::jsonBool(memberConfig["activeBridge"],false)) { + if (OSUtils::jsonBool(memberConfig["activeBridge"],false)) nw->activeBridgeMembers.insert(memberId); - } isAuth = OSUtils::jsonBool(memberConfig["authorized"],false); - if (isAuth) { - Metrics::member_auths++; + if (isAuth) nw->authorizedMembers.insert(memberId); - } json &ips = memberConfig["ipAssignments"]; if (ips.is_array()) { for(unsigned long i=0;i ll(_changeListeners_l); + std::lock_guard ll(_changeListeners_l); for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) { (*i)->onNetworkMemberUpdate(this,networkId,memberId,memberConfig); } } } else if (memberId) { if (nw) { - std::unique_lock l(nw->lock); + std::lock_guard l(nw->lock); nw->members.erase(memberId); } if (networkId) { - std::unique_lock l(_networks_l); + std::lock_guard l(_networks_l); auto er = _networkByMember.equal_range(memberId); for(auto i=er.first;i!=er.second;++i) { if (i->second == networkId) { @@ -316,26 +293,8 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no } } - if (notifyListeners) { - if(networkId != 0 && memberId != 0 && old.is_object() && !memberConfig.is_object()) { - // member delete - Metrics::member_count--; - } else if (networkId != 0 && memberId != 0 && !old.is_object() && memberConfig.is_object()) { - // new member - Metrics::member_count++; - } - - if (!wasAuth && isAuth) { - Metrics::member_auths++; - } else if (wasAuth && !isAuth) { - Metrics::member_deauths++; - } else { - Metrics::member_changes++; - } - } - if ((notifyListeners)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId))) { - std::unique_lock ll(_changeListeners_l); + std::lock_guard ll(_changeListeners_l); for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) { (*i)->onNetworkMemberDeauthorize(this,networkId,memberId); } @@ -344,35 +303,24 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) { - Metrics::db_network_change++; - if (notifyListeners) { - if (old.is_object() && old.contains("id") && networkConfig.is_object() && networkConfig.contains("id")) { - Metrics::network_changes++; - } else if (!old.is_object() && networkConfig.is_object() && networkConfig.contains("id")) { - Metrics::network_count++; - } else if (old.is_object() && old.contains("id") && !networkConfig.is_object()) { - Metrics::network_count--; - } - } - if (networkConfig.is_object()) { const std::string ids = networkConfig["id"]; const uint64_t networkId = Utils::hexStrToU64(ids.c_str()); if (networkId) { std::shared_ptr<_Network> nw; { - std::unique_lock l(_networks_l); + std::lock_guard l(_networks_l); std::shared_ptr<_Network> &nw2 = _networks[networkId]; if (!nw2) nw2.reset(new _Network); nw = nw2; } { - std::unique_lock l2(nw->lock); + std::lock_guard l2(nw->lock); nw->config = networkConfig; } if (notifyListeners) { - std::unique_lock ll(_changeListeners_l); + std::lock_guard ll(_changeListeners_l); for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) { (*i)->onNetworkUpdate(this,networkId,networkConfig); } @@ -382,25 +330,7 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool const std::string ids = old["id"]; const uint64_t networkId = Utils::hexStrToU64(ids.c_str()); if (networkId) { - try { - // deauth all members on the network - nlohmann::json network; - std::vector members; - this->get(networkId, network, members); - for(auto i=members.begin();i!=members.end();++i) { - const std::string nodeID = (*i)["id"]; - const uint64_t memberId = Utils::hexStrToU64(nodeID.c_str()); - std::unique_lock ll(_changeListeners_l); - for(auto j=_changeListeners.begin();j!=_changeListeners.end();++j) { - (*j)->onNetworkMemberDeauthorize(this,networkId,memberId); - } - } - } catch (std::exception &e) { - std::cerr << "Error deauthorizing members on network delete: " << e.what() << std::endl; - } - - // delete the network - std::unique_lock l(_networks_l); + std::lock_guard l(_networks_l); _networks.erase(networkId); } } diff --git a/controller/DB.hpp b/controller/DB.hpp index 50a57be6..8a3c05e0 100644 --- a/controller/DB.hpp +++ b/controller/DB.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -29,47 +29,14 @@ #include #include #include -#include +#include #include -#include -#include - -#include - -#define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000 +#include "../ext/json/json.hpp" namespace ZeroTier { -struct AuthInfo -{ -public: - AuthInfo() - : enabled(false) - , version(0) - , authenticationURL() - , authenticationExpiryTime(0) - , issuerURL() - , centralAuthURL() - , ssoNonce() - , ssoState() - , ssoClientID() - , ssoProvider("default") - {} - - bool enabled; - uint64_t version; - std::string authenticationURL; - uint64_t authenticationExpiryTime; - std::string issuerURL; - std::string centralAuthURL; - std::string ssoNonce; - std::string ssoState; - std::string ssoClientID; - std::string ssoProvider; -}; - /** * Base class with common infrastructure for all controller DB implementations */ @@ -109,7 +76,7 @@ public: inline bool hasNetwork(const uint64_t networkId) const { - std::shared_lock l(_networks_l); + std::lock_guard l(_networks_l); return (_networks.find(networkId) != _networks.end()); } @@ -124,7 +91,7 @@ public: inline void each(F f) { nlohmann::json nullJson; - std::unique_lock lck(_networks_l); + std::lock_guard lck(_networks_l); for(auto nw=_networks.begin();nw!=_networks.end();++nw) { f(nw->first,nw->second->config,0,nullJson); // first provide network with 0 for member ID for(auto m=nw->second->members.begin();m!=nw->second->members.end();++m) { @@ -134,15 +101,15 @@ public: } virtual bool save(nlohmann::json &record,bool notifyListeners) = 0; + virtual void eraseNetwork(const uint64_t networkId) = 0; virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0; - virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0; - virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); } + virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0; inline void addListener(DB::ChangeListener *const listener) { - std::unique_lock l(_changeListeners_l); + std::lock_guard l(_changeListeners_l); _changeListeners.push_back(listener); } @@ -178,18 +145,18 @@ protected: std::unordered_set authorizedMembers; std::unordered_set allocatedIps; int64_t mostRecentDeauthTime; - std::shared_mutex lock; + std::mutex lock; }; - virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners); - virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners); + void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners); + void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners); void _fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info); std::vector _changeListeners; std::unordered_map< uint64_t,std::shared_ptr<_Network> > _networks; std::unordered_multimap< uint64_t,uint64_t > _networkByMember; - mutable std::shared_mutex _changeListeners_l; - mutable std::shared_mutex _networks_l; + mutable std::mutex _changeListeners_l; + mutable std::mutex _networks_l; }; } // namespace ZeroTier diff --git a/controller/DBMirrorSet.cpp b/controller/DBMirrorSet.cpp index 78fa82a4..c467e171 100644 --- a/controller/DBMirrorSet.cpp +++ b/controller/DBMirrorSet.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -15,12 +15,9 @@ namespace ZeroTier { -DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) - : _listener(listener) - , _running(true) - , _syncCheckerThread() - , _dbs() - , _dbs_l() +DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) : + _listener(listener), + _running(true) { _syncCheckerThread = std::thread([this]() { for(;;) { @@ -32,7 +29,7 @@ DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) std::vector< std::shared_ptr > dbs; { - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); if (_dbs.size() <= 1) continue; // no need to do this if there's only one DB, so skip the iteration dbs = _dbs; @@ -79,7 +76,7 @@ DBMirrorSet::~DBMirrorSet() bool DBMirrorSet::hasNetwork(const uint64_t networkId) const { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if ((*d)->hasNetwork(networkId)) return true; @@ -89,7 +86,7 @@ bool DBMirrorSet::hasNetwork(const uint64_t networkId) const bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network) { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if ((*d)->get(networkId,network)) { return true; @@ -100,7 +97,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network) bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member) { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if ((*d)->get(networkId,network,memberId,member)) return true; @@ -110,7 +107,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uin bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info) { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if ((*d)->get(networkId,network,memberId,member,info)) return true; @@ -120,7 +117,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uin bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vector &members) { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if ((*d)->get(networkId,network,members)) return true; @@ -128,21 +125,9 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vect return false; } -AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) -{ - std::shared_lock l(_dbs_l); - for(auto d=_dbs.begin();d!=_dbs.end();++d) { - AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL); - if (info.enabled) { - return info; - } - } - return AuthInfo(); -} - void DBMirrorSet::networks(std::set &networks) { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { (*d)->networks(networks); } @@ -151,7 +136,7 @@ void DBMirrorSet::networks(std::set &networks) bool DBMirrorSet::waitForReady() { bool r = false; - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { r |= (*d)->waitForReady(); } @@ -160,7 +145,7 @@ bool DBMirrorSet::waitForReady() bool DBMirrorSet::isReady() { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if (!(*d)->isReady()) return false; @@ -172,7 +157,7 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners) { std::vector< std::shared_ptr > dbs; { - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); dbs = _dbs; } if (notifyListeners) { @@ -192,7 +177,7 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners) void DBMirrorSet::eraseNetwork(const uint64_t networkId) { - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { (*d)->eraseNetwork(networkId); } @@ -200,7 +185,7 @@ void DBMirrorSet::eraseNetwork(const uint64_t networkId) void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId) { - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { (*d)->eraseMember(networkId,memberId); } @@ -208,7 +193,7 @@ void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId) void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) { - std::shared_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { (*d)->nodeIsOnline(networkId,memberId,physicalAddress); } @@ -217,7 +202,7 @@ void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId, void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) { nlohmann::json record(network); - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if (d->get() != db) { (*d)->save(record,false); @@ -229,7 +214,7 @@ void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohma void DBMirrorSet::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) { nlohmann::json record(member); - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); for(auto d=_dbs.begin();d!=_dbs.end();++d) { if (d->get() != db) { (*d)->save(record,false); diff --git a/controller/DBMirrorSet.hpp b/controller/DBMirrorSet.hpp index 88814404..6ca6c452 100644 --- a/controller/DBMirrorSet.hpp +++ b/controller/DBMirrorSet.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -51,12 +51,10 @@ public: virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member); virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId); - AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL); - inline void addDB(const std::shared_ptr &db) { db->addListener(this); - std::unique_lock l(_dbs_l); + std::lock_guard l(_dbs_l); _dbs.push_back(db); } @@ -65,7 +63,7 @@ private: std::atomic_bool _running; std::thread _syncCheckerThread; std::vector< std::shared_ptr< DB > > _dbs; - mutable std::shared_mutex _dbs_l; + mutable std::mutex _dbs_l; }; } // namespace ZeroTier diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 14c37250..0b6c4405 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -16,7 +16,6 @@ #include #include #include -#include #ifndef _WIN32 #include @@ -29,12 +28,15 @@ #include #include #include -#include -#include -#include + +#include "../node/Constants.hpp" +#include "../node/Node.hpp" +#include "../node/CertificateOfMembership.hpp" +#include "../node/NetworkConfig.hpp" +#include "../node/Dictionary.hpp" +#include "../node/MAC.hpp" #include "../include/ZeroTierOne.h" -#include "../version.h" #include "EmbeddedNetworkController.hpp" #include "LFDB.hpp" @@ -43,12 +45,6 @@ #include "PostgreSQL.hpp" #endif -#include "../node/Node.hpp" -#include "../node/CertificateOfMembership.hpp" -#include "../node/NetworkConfig.hpp" -#include "../node/Dictionary.hpp" -#include "../node/MAC.hpp" - using json = nlohmann::json; // API version reported via JSON control plane @@ -101,7 +97,7 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) break; } - if (r.empty()) { + if (r.size() == 0) { switch(rt) { case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: r["type"] = "MATCH_SOURCE_ZEROTIER_ADDRESS"; @@ -243,7 +239,7 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) break; } - if (!r.empty()) { + if (r.size() > 0) { r["not"] = ((rule.t & 0x80) != 0); r["or"] = ((rule.t & 0x40) != 0); } @@ -315,14 +311,12 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) return true; } else if (t == "MATCH_MAC_SOURCE") { rule.t |= ZT_NETWORK_RULE_MATCH_MAC_SOURCE; - std::string mac(OSUtils::jsonString(r["mac"],"0")); - Utils::cleanMac(mac); + const std::string mac(OSUtils::jsonString(r["mac"],"0")); Utils::unhex(mac.c_str(),(unsigned int)mac.length(),rule.v.mac,6); return true; } else if (t == "MATCH_MAC_DEST") { rule.t |= ZT_NETWORK_RULE_MATCH_MAC_DEST; - std::string mac(OSUtils::jsonString(r["mac"],"0")); - Utils::cleanMac(mac); + const std::string mac(OSUtils::jsonString(r["mac"],"0")); Utils::unhex(mac.c_str(),(unsigned int)mac.length(),rule.v.mac,6); return true; } else if (t == "MATCH_IPV4_SOURCE") { @@ -462,51 +456,15 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) } // anonymous namespace -EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, RedisConfig *rc) - : _startTime(OSUtils::now()) - , _listenPort(listenPort) - , _node(node) - , _ztPath(ztPath) - , _path(dbPath) - , _signingId() - , _signingIdAddressString() - , _sender((NetworkController::Sender *)0) - , _db(this) - , _queue() - , _threads() - , _threads_l() - , _memberStatus() - , _memberStatus_l() - , _expiringSoon() - , _expiringSoon_l() - , _rc(rc) - , _ssoExpiryRunning(true) - , _ssoExpiry(std::thread(&EmbeddedNetworkController::_ssoExpiryThread, this)) - -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - , _member_status_lookup{"nc_member_status_lookup",""} - , _member_status_lookup_count{"nc_member_status_lookup_count",""} - , _node_is_online{"nc_node_is_online",""} - , _node_is_online_count{"nc_node_is_online_count",""} - , _get_and_init_member{"nc_get_and_init_member",""} - , _get_and_init_member_count{"nc_get_and_init_member_count",""} - , _have_identity{"nc_have_identity",""} - , _have_identity_count{"nc_have_identity_count",""} - , _determine_auth{"nc_determine_auth",""} - , _determine_auth_count{"nc_determine_auth_count",""} - , _sso_check{"nc_sso_check",""} - , _sso_check_count{"nc_sso_check_count",""} - , _auth_check{"nc_auth_check",""} - , _auth_check_count{"nc_auth_check_count",""} - , _json_schlep{"nc_json_schlep",""} - , _json_schlep_count{"nc_json_schlep_count",""} - , _issue_certificate{"nc_issue_certificate", ""} - , _issue_certificate_count{"nc_issue_certificate_count",""} - , _save_member{"nc_save_member",""} - , _save_member_count{"nc_save_member_count",""} - , _send_netconf{"nc_send_netconf2",""} - , _send_netconf_count{"nc_send_netconf2_count",""} -#endif +EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc) : + _startTime(OSUtils::now()), + _listenPort(listenPort), + _node(node), + _ztPath(ztPath), + _path(dbPath), + _sender((NetworkController::Sender *)0), + _db(this), + _mqc(mqc) { } @@ -514,15 +472,8 @@ EmbeddedNetworkController::~EmbeddedNetworkController() { std::lock_guard l(_threads_l); _queue.stop(); - for(auto t=_threads.begin();t!=_threads.end();++t) { + for(auto t=_threads.begin();t!=_threads.end();++t) t->join(); - } - _ssoExpiryRunning = false; - _ssoExpiry.join(); -} - -void EmbeddedNetworkController::setSSORedirectURL(const std::string &url) { - _ssoRedirectURL = url; } void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender) @@ -534,7 +485,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, _rc))); + _db.addDB(std::shared_ptr(new PostgreSQL(_signingId,_path.substr(9).c_str(), _listenPort, _mqc))); } else { #endif _db.addDB(std::shared_ptr(new FileDB(_path.c_str()))); @@ -585,18 +536,6 @@ void EmbeddedNetworkController::request( if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; _startThreads(); - - const int64_t now = OSUtils::now(); - - if (requestPacketId) { - std::lock_guard l(_memberStatus_l); - _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; - if ((now - ms.lastRequestTime) <= ZT_NETCONF_MIN_REQUEST_PERIOD) { - return; - } - ms.lastRequestTime = now; - } - _RQEntry *qe = new _RQEntry; qe->nwid = nwid; qe->requestPacketId = requestPacketId; @@ -607,726 +546,565 @@ void EmbeddedNetworkController::request( _queue.post(qe); } -std::string EmbeddedNetworkController::networkUpdateFromPostData(uint64_t networkID, const std::string &body) +unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( + const std::vector &path, + const std::string &body, + std::string &responseBody, + std::string &responseContentType) { - json b = OSUtils::jsonParse(body); + if ((path.size() > 0)&&(path[0] == "network")) { - char nwids[24]; - OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", networkID); + if ((path.size() >= 2)&&(path[1].length() == 16)) { + const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); + json network; + if (!_db.get(nwid,network)) + return 404; - json network; - _db.get(networkID, network); - DB::initNetwork(network); - if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); - if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); - if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); - if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); - if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); + if (path.size() >= 3) { - if (b.count("remoteTraceTarget")) { - const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); - if (rtt.length() == 10) { - network["remoteTraceTarget"] = rtt; - } else { - network["remoteTraceTarget"] = json(); - } - } - if (b.count("remoteTraceLevel")) network["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL); + if (path[2] == "member") { - if (b.count("v4AssignMode")) { - json nv4m; - json &v4m = b["v4AssignMode"]; - if (v4m.is_string()) { // backward compatibility - nv4m["zt"] = (OSUtils::jsonString(v4m,"") == "zt"); - } else if (v4m.is_object()) { - nv4m["zt"] = OSUtils::jsonBool(v4m["zt"],false); - } else nv4m["zt"] = false; - network["v4AssignMode"] = nv4m; - } + if (path.size() >= 4) { + // Get member - if (b.count("v6AssignMode")) { - json nv6m; - json &v6m = b["v6AssignMode"]; - if (!nv6m.is_object()) nv6m = json::object(); - if (v6m.is_string()) { // backward compatibility - std::vector v6ms(OSUtils::split(OSUtils::jsonString(v6m,"").c_str(),",","","")); - std::sort(v6ms.begin(),v6ms.end()); - v6ms.erase(std::unique(v6ms.begin(),v6ms.end()),v6ms.end()); - nv6m["rfc4193"] = false; - nv6m["zt"] = false; - nv6m["6plane"] = false; - for(std::vector::iterator i(v6ms.begin());i!=v6ms.end();++i) { - if (*i == "rfc4193") - nv6m["rfc4193"] = true; - else if (*i == "zt") - nv6m["zt"] = true; - else if (*i == "6plane") - nv6m["6plane"] = true; - } - } else if (v6m.is_object()) { - if (v6m.count("rfc4193")) nv6m["rfc4193"] = OSUtils::jsonBool(v6m["rfc4193"],false); - if (v6m.count("zt")) nv6m["zt"] = OSUtils::jsonBool(v6m["zt"],false); - if (v6m.count("6plane")) nv6m["6plane"] = OSUtils::jsonBool(v6m["6plane"],false); - } else { - nv6m["rfc4193"] = false; - nv6m["zt"] = false; - nv6m["6plane"] = false; - } - network["v6AssignMode"] = nv6m; - } + const uint64_t address = Utils::hexStrToU64(path[3].c_str()); + json member; + if (!_db.get(nwid,network,address,member)) + return 404; + responseBody = OSUtils::jsonDump(member); + responseContentType = "application/json"; - if (b.count("routes")) { - json &rts = b["routes"]; - if (rts.is_array()) { - json nrts = json::array(); - for(unsigned long i=0;i().c_str()); - InetAddress v; - if (via.is_string()) v.fromString(via.get().c_str()); - if ( ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) && (t.netmaskBitsValid()) ) { - json tmp; - char tmp2[64]; - tmp["target"] = t.toString(tmp2); - if (v.ss_family == t.ss_family) - tmp["via"] = v.toIpString(tmp2); - else tmp["via"] = json(); - nrts.push_back(tmp); - if (nrts.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; + } else { + // List members and their revisions + + responseBody = "{"; + std::vector members; + if (_db.get(nwid,network,members)) { + responseBody.reserve((members.size() + 2) * 32); + std::string mid; + for(auto member=members.begin();member!=members.end();++member) { + mid = (*member)["id"]; + char tmp[128]; + OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s\"%s\":%llu",(responseBody.length() > 1) ? "," : "",mid.c_str(),(unsigned long long)OSUtils::jsonInt((*member)["revision"],0)); + responseBody.append(tmp); + } } + responseBody.push_back('}'); + responseContentType = "application/json"; + } - } + return 200; + + } // else 404 + + } else { + // Get network + + responseBody = OSUtils::jsonDump(network); + responseContentType = "application/json"; + return 200; + } - network["routes"] = nrts; - } + } else if (path.size() == 1) { + // List networks + + std::set networkIds; + _db.networks(networkIds); + char tmp[64]; + responseBody = "["; + responseBody.reserve((networkIds.size() + 1) * 24); + for(std::set::const_iterator i(networkIds.begin());i!=networkIds.end();++i) { + if (responseBody.length() > 1) + responseBody.push_back(','); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"\"%.16llx\"",(unsigned long long)*i); + responseBody.append(tmp); + } + responseBody.push_back(']'); + responseContentType = "application/json"; + + return 200; + + } // else 404 + + } else { + // Controller status + + char tmp[4096]; + const bool dbOk = _db.isReady(); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"databaseReady\": %s\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),dbOk ? "true" : "false"); + responseBody = tmp; + responseContentType = "application/json"; + return dbOk ? 200 : 503; + } - if (b.count("ipAssignmentPools")) { - json &ipp = b["ipAssignmentPools"]; - if (ipp.is_array()) { - json nipp = json::array(); - for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - } - } - network["ipAssignmentPools"] = nipp; + return 404; +} + +unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( + const std::vector &path, + const std::string &body, + std::string &responseBody, + std::string &responseContentType) +{ + if (path.empty()) + return 404; + + json b; + try { + b = OSUtils::jsonParse(body); + if (!b.is_object()) { + responseBody = "{ \"message\": \"body is not a JSON object\" }"; + responseContentType = "application/json"; + return 400; } + } catch ( ... ) { + responseBody = "{ \"message\": \"body JSON is invalid\" }"; + responseContentType = "application/json"; + return 400; } + const int64_t now = OSUtils::now(); - if (b.count("rules")) { - json &rules = b["rules"]; - if (rules.is_array()) { - json nrules = json::array(); - for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - } - } - network["rules"] = nrules; - } - } + if (path[0] == "network") { - if (b.count("authTokens")) { - json &authTokens = b["authTokens"]; - if (authTokens.is_object()) { - json nat; - for(json::iterator t(authTokens.begin());t!=authTokens.end();++t) { - if ((t.value().is_number())&&(t.value() >= 0)) - nat[t.key()] = t.value(); - } - network["authTokens"] = nat; - } else { - network["authTokens"] = {{}}; - } - } + if ((path.size() >= 2)&&(path[1].length() == 16)) { + uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); + char nwids[24]; + OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); - if (b.count("capabilities")) { - json &capabilities = b["capabilities"]; - if (capabilities.is_array()) { - std::map< uint64_t,json > ncaps; - for(unsigned long i=0;i= 3) { - json &rules = cap["rules"]; - json nrules = json::array(); - if (rules.is_array()) { - for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; + if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { + uint64_t address = Utils::hexStrToU64(path[3].c_str()); + char addrs[24]; + OSUtils::ztsnprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address); + + json member,network; + _db.get(nwid,network,address,member); + DB::initMember(member); + + try { + if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false); + if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"],false); + + if (b.count("remoteTraceTarget")) { + const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + member["remoteTraceTarget"] = rtt; + } else { + member["remoteTraceTarget"] = json(); + } + } + if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL); + + if (b.count("authorized")) { + const bool newAuth = OSUtils::jsonBool(b["authorized"],false); + if (newAuth != OSUtils::jsonBool(member["authorized"],false)) { + member["authorized"] = newAuth; + member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = now; + if (newAuth) { + member["lastAuthorizedCredentialType"] = "api"; + member["lastAuthorizedCredential"] = json(); } } } - } - ncap["rules"] = nrules; - ncaps[capId] = ncap; - } - } - - json ncapsa = json::array(); - for(std::map< uint64_t,json >::iterator c(ncaps.begin());c!=ncaps.end();++c) { - ncapsa.push_back(c->second); - if (ncapsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - network["capabilities"] = ncapsa; - } - } - - if (b.count("tags")) { - json &tags = b["tags"]; - if (tags.is_array()) { - std::map< uint64_t,json > ntags; - for(unsigned long i=0;i::iterator t(ntags.begin());t!=ntags.end();++t) { - ntagsa.push_back(t->second); - if (ntagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - network["tags"] = ntagsa; - } - } - - if (b.count("dns")) { - json &dns = b["dns"]; - if (dns.is_object()) { - json nd; - - nd["domain"] = dns["domain"]; - - json &srv = dns["servers"]; - if (srv.is_array()) { - json ns = json::array(); - for(unsigned int i=0;i setContent) -{ - // Control plane Endpoints - std::string controllerPath = "/controller"; - std::string networkListPath = "/controller/network"; - std::string networkListPath2 = "/unstable/controller/network"; - std::string networkPath = "/controller/network/([0-9a-fA-F]{16})"; - std::string oldAndBustedNetworkCreatePath = "/controller/network/([0-9a-fA-F]{10})______"; - std::string memberListPath = "/controller/network/([0-9a-fA-F]{16})/member"; - std::string memberListPath2 = "/unstable/controller/network/([0-9a-fA-F]{16})/member"; - std::string memberPath = "/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})"; - - - auto controllerGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - char tmp[4096]; - const bool dbOk = _db.isReady(); - OSUtils::ztsnprintf( - tmp, - sizeof(tmp), - "{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"databaseReady\": %s\n}\n", - ZT_NETCONF_CONTROLLER_API_VERSION, - (unsigned long long)OSUtils::now(), - dbOk ? "true" : "false"); - - if (!dbOk) { - res.status = 503; - } - - setContent(req, res, tmp); - }; - s.Get(controllerPath, controllerGet); - sv6.Get(controllerPath, controllerGet); - - auto networkListGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - std::set networkIds; - _db.networks(networkIds); - char tmp[64]; - - auto out = json::array(); - for(std::set::const_iterator i(networkIds.begin()); i != networkIds.end(); ++i) { - OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", *i); - out.push_back(tmp); - } - - setContent(req, res, out.dump()); - }; - s.Get(networkListPath, networkListGet); - sv6.Get(networkListPath, networkListGet); - - auto networkListGet2 = [&, setContent](const httplib::Request &req, httplib::Response &res) { - std::set networkIds; - _db.networks(networkIds); - - auto meta = json::object(); - auto data = json::array(); - uint64_t networkCount = 0; - - for(std::set::const_iterator nwid(networkIds.begin()); nwid != networkIds.end(); ++nwid) { - json network; - if (!_db.get(*nwid, network)) { - continue; - } - - std::vector memTmp; - if (_db.get(*nwid, network, memTmp)) { - if (!network.is_null()) { - uint64_t authorizedCount = 0; - uint64_t totalCount = memTmp.size(); - networkCount++; - - for (auto m = memTmp.begin(); m != memTmp.end(); ++m) { - bool a = OSUtils::jsonBool((*m)["authorized"], 0); - if (a) { authorizedCount++; } - } - - auto nwMeta = json::object(); - nwMeta["totalMemberCount"] = totalCount; - nwMeta["authorizedMemberCount"] = authorizedCount; - network["meta"] = nwMeta; - - data.push_back(network); - } - } - } - meta["networkCount"] = networkCount; - - auto out = json::object(); - out["data"] = data; - out["meta"] = meta; - - setContent(req, res, out.dump()); - }; - s.Get(networkListPath2, networkListGet2); - sv6.Get(networkListPath2, networkListGet2); - - auto networkGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1]; - uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str()); - json network; - if (!_db.get(nwid, network)) { - res.status = 404; - return; - } - - setContent(req, res, network.dump()); - }; - s.Get(networkPath, networkGet); - sv6.Get(networkPath, networkGet); - - auto createNewNetwork = [&, setContent](const httplib::Request &req, httplib::Response &res) { - // fprintf(stderr, "creating new network (new style)\n"); - uint64_t nwid = 0; - uint64_t nwidPrefix = (Utils::hexStrToU64(_signingIdAddressString.c_str()) << 24) & 0xffffffffff000000ULL; - uint64_t nwidPostfix = 0; - for(unsigned long k=0;k<100000;++k) { // sanity limit on trials - Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix)); - uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL); - if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL; - if (!_db.hasNetwork(tryNwid)) { - nwid = tryNwid; - break; - } - } - if (!nwid) { - res.status = 503; - return; - } - - setContent(req, res, networkUpdateFromPostData(nwid, req.body)); - }; - s.Put(networkListPath, createNewNetwork); - s.Post(networkListPath, createNewNetwork); - sv6.Put(networkListPath, createNewNetwork); - sv6.Post(networkListPath, createNewNetwork); - - auto createNewNetworkOldAndBusted = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto inID = req.matches[1].str(); - - if (inID != _signingIdAddressString) { - res.status = 400; - return; - } - - uint64_t nwid = 0; - uint64_t nwidPrefix = (Utils::hexStrToU64(inID.c_str()) << 24) & 0xffffffffff000000ULL; - uint64_t nwidPostfix = 0; - for(unsigned long k=0;k<100000;++k) { // sanity limit on trials - Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix)); - uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL); - if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL; - if (!_db.hasNetwork(tryNwid)) { - nwid = tryNwid; - break; - } - } - if (!nwid) { - res.status = 503; - return; - } - setContent(req, res, networkUpdateFromPostData(nwid, req.body)); - }; - s.Put(oldAndBustedNetworkCreatePath, createNewNetworkOldAndBusted); - s.Post(oldAndBustedNetworkCreatePath, createNewNetworkOldAndBusted); - sv6.Put(oldAndBustedNetworkCreatePath, createNewNetworkOldAndBusted); - sv6.Post(oldAndBustedNetworkCreatePath, createNewNetworkOldAndBusted); - - auto networkPost = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1].str(); - uint64_t nwid = Utils::hexStrToU64(networkID.c_str()); - - res.status = 200; - setContent(req, res, networkUpdateFromPostData(nwid, req.body)); - }; - s.Put(networkPath, networkPost); - s.Post(networkPath, networkPost); - sv6.Put(networkPath, networkPost); - sv6.Post(networkPath, networkPost); - - auto networkDelete = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1].str(); - uint64_t nwid = Utils::hexStrToU64(networkID.c_str()); - - json network; - if (!_db.get(nwid,network)) { - res.status = 404; - return; - } - - _db.eraseNetwork(nwid); - setContent(req, res, network.dump()); - }; - s.Delete(networkPath, networkDelete); - sv6.Delete(networkPath, networkDelete); - - auto memberListGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1]; - uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str()); - json network; - if (!_db.get(nwid, network)) { - res.status = 404; - return; - } - - json out = json::object(); - std::vector memTmp; - if (_db.get(nwid, network, memTmp)) { - for (auto m = memTmp.begin(); m != memTmp.end(); ++m) { - int revision = OSUtils::jsonInt((*m)["revision"], 0); - std::string id = OSUtils::jsonString((*m)["id"], ""); - if (id.length() == 10) { - out[id] = revision; - } - } - } - - setContent(req, res, out.dump()); - }; - s.Get(memberListPath, memberListGet); - sv6.Get(memberListPath, memberListGet); - - auto memberListGet2 = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1]; - uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str()); - json network; - if (!_db.get(nwid, network)) { - res.status = 404; - return; - } - - auto out = nlohmann::json::object(); - auto meta = nlohmann::json::object(); - std::vector memTmp; - if (_db.get(nwid, network, memTmp)) { - uint64_t authorizedCount = 0; - uint64_t totalCount = memTmp.size(); - for (auto m = memTmp.begin(); m != memTmp.end(); ++m) { - bool a = OSUtils::jsonBool((*m)["authorized"], 0); - if (a) { authorizedCount++; } - } - - meta["totalCount"] = totalCount; - meta["authorizedCount"] = authorizedCount; - - out["data"] = memTmp; - out["meta"] = meta; - - setContent(req, res, out.dump()); - } else { - res.status = 404; - return; - } - }; - s.Get(memberListPath2, memberListGet2); - sv6.Get(memberListPath2, memberListGet2); - - auto memberGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1]; - auto memberID = req.matches[2]; - uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str()); - uint64_t memid = Utils::hexStrToU64(memberID.str().c_str()); - json network; - json member; - if (!_db.get(nwid, network, memid, member)) { - res.status = 404; - return; - } - - setContent(req, res, member.dump()); - }; - s.Get(memberPath, memberGet); - sv6.Get(memberPath, memberGet); - - auto memberPost = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1].str(); - auto memberID = req.matches[2].str(); - uint64_t nwid = Utils::hexStrToU64(networkID.c_str()); - uint64_t memid = Utils::hexStrToU64(memberID.c_str()); - - if (!_db.hasNetwork(nwid)) { - res.status = 404; - return; - } - - json network; - json member; - _db.get(nwid, network, memid, member); - DB::initMember(member); - - json b = OSUtils::jsonParse(req.body); - - if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"], false); - if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false); - if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL); - if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], ""); - if (b.count("name")) member["name"] = OSUtils::jsonString(b["name"], ""); - - if (b.count("remoteTraceTarget")) { - const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); - if (rtt.length() == 10) { - member["remoteTraceTarget"] = rtt; - } else { - member["remoteTraceTarget"] = json(); - } - } - if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL); - - if (b.count("authorized")) { - const bool newAuth = OSUtils::jsonBool(b["authorized"],false); - if (newAuth != OSUtils::jsonBool(member["authorized"],false)) { - member["authorized"] = newAuth; - member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = OSUtils::now(); - if (newAuth) { - member["lastAuthorizedCredentialType"] = "api"; - member["lastAuthorizedCredential"] = json(); - } - } - } - - if (b.count("ipAssignments")) { - json &ipa = b["ipAssignments"]; - if (ipa.is_array()) { - json mipa(json::array()); - for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - } - member["ipAssignments"] = mipa; - } - } - - if (b.count("tags")) { - json &tags = b["tags"]; - if (tags.is_array()) { - std::map mtags; - for(unsigned long i=0;i::iterator t(mtags.begin());t!=mtags.end();++t) { - json ta = json::array(); - ta.push_back(t->first); - ta.push_back(t->second); - mtagsa.push_back(ta); - if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - member["tags"] = mtagsa; - } - } - - if (b.count("capabilities")) { - json &capabilities = b["capabilities"]; - if (capabilities.is_array()) { - json mcaps = json::array(); - for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - std::sort(mcaps.begin(),mcaps.end()); - mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end()); - member["capabilities"] = mcaps; - } - } - - member["id"] = memberID; - member["address"] = memberID; - member["nwid"] = networkID; - - DB::cleanMember(member); - _db.save(member, true); - - setContent(req, res, member.dump()); - }; - s.Put(memberPath, memberPost); - s.Post(memberPath, memberPost); - sv6.Put(memberPath, memberPost); - sv6.Post(memberPath, memberPost); - - auto memberDelete = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto networkID = req.matches[1].str(); - auto memberID = req.matches[2].str(); - - uint64_t nwid = Utils::hexStrToU64(networkID.c_str()); - uint64_t address = Utils::hexStrToU64(memberID.c_str()); - json network, member; - - if (!_db.get(nwid, network, address, member)) { - res.status = 404; - return; - } - - if (!member.size()) { - res.status = 404; - return; - } - - _db.eraseMember(nwid, address); - - setContent(req, res, member.dump()); - }; - s.Delete(memberPath, memberDelete); - sv6.Delete(memberPath, memberDelete); -} - -void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) -{ - static volatile unsigned long idCounter = 0; - char id[128],tmp[128]; - std::string k,v; - - try { - // Convert Dictionary into JSON object - json d; - char *saveptr = (char *)0; - for(char *l=Utils::stok(rt.data,"\n",&saveptr);(l);l=Utils::stok((char *)0,"\n",&saveptr)) { - char *eq = strchr(l,'='); - if (eq > l) { - k.assign(l,(unsigned long)(eq - l)); - v.clear(); - ++eq; - while (*eq) { - if (*eq == '\\') { - ++eq; - if (*eq) { - switch(*eq) { - case 'r': v.push_back('\r'); break; - case 'n': v.push_back('\n'); break; - case '0': v.push_back((char)0); break; - case 'e': v.push_back('='); break; - default: v.push_back(*eq); break; + if (b.count("ipAssignments")) { + json &ipa = b["ipAssignments"]; + if (ipa.is_array()) { + json mipa(json::array()); + for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + } + member["ipAssignments"] = mipa; } - ++eq; } - } else { - v.push_back(*(eq++)); + + if (b.count("tags")) { + json &tags = b["tags"]; + if (tags.is_array()) { + std::map mtags; + for(unsigned long i=0;i::iterator t(mtags.begin());t!=mtags.end();++t) { + json ta = json::array(); + ta.push_back(t->first); + ta.push_back(t->second); + mtagsa.push_back(ta); + if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + member["tags"] = mtagsa; + } + } + + if (b.count("capabilities")) { + json &capabilities = b["capabilities"]; + if (capabilities.is_array()) { + json mcaps = json::array(); + for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + std::sort(mcaps.begin(),mcaps.end()); + mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end()); + member["capabilities"] = mcaps; + } + } + } catch ( ... ) { + responseBody = "{ \"message\": \"exception while processing parameters in JSON body\" }"; + responseContentType = "application/json"; + return 400; + } + + member["id"] = addrs; + member["address"] = addrs; // legacy + member["nwid"] = nwids; + + DB::cleanMember(member); + _db.save(member,true); + responseBody = OSUtils::jsonDump(member); + responseContentType = "application/json"; + + return 200; + } // else 404 + + } else { + // POST to network ID + + // Magic ID ending with ______ picks a random unused network ID + if (path[1].substr(10) == "______") { + nwid = 0; + uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL; + uint64_t nwidPostfix = 0; + for(unsigned long k=0;k<100000;++k) { // sanity limit on trials + Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix)); + uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL); + if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL; + if (!_db.hasNetwork(tryNwid)) { + nwid = tryNwid; + break; + } + } + if (!nwid) + return 503; + } + OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid); + + json network; + _db.get(nwid,network); + DB::initNetwork(network); + + try { + if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); + if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); + if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); + if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); + if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); + + if (b.count("remoteTraceTarget")) { + const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],"")); + if (rtt.length() == 10) { + network["remoteTraceTarget"] = rtt; + } else { + network["remoteTraceTarget"] = json(); + } + } + if (b.count("remoteTraceLevel")) network["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL); + + if (b.count("v4AssignMode")) { + json nv4m; + json &v4m = b["v4AssignMode"]; + if (v4m.is_string()) { // backward compatibility + nv4m["zt"] = (OSUtils::jsonString(v4m,"") == "zt"); + } else if (v4m.is_object()) { + nv4m["zt"] = OSUtils::jsonBool(v4m["zt"],false); + } else nv4m["zt"] = false; + network["v4AssignMode"] = nv4m; + } + + if (b.count("v6AssignMode")) { + json nv6m; + json &v6m = b["v6AssignMode"]; + if (!nv6m.is_object()) nv6m = json::object(); + if (v6m.is_string()) { // backward compatibility + std::vector v6ms(OSUtils::split(OSUtils::jsonString(v6m,"").c_str(),",","","")); + std::sort(v6ms.begin(),v6ms.end()); + v6ms.erase(std::unique(v6ms.begin(),v6ms.end()),v6ms.end()); + nv6m["rfc4193"] = false; + nv6m["zt"] = false; + nv6m["6plane"] = false; + for(std::vector::iterator i(v6ms.begin());i!=v6ms.end();++i) { + if (*i == "rfc4193") + nv6m["rfc4193"] = true; + else if (*i == "zt") + nv6m["zt"] = true; + else if (*i == "6plane") + nv6m["6plane"] = true; + } + } else if (v6m.is_object()) { + if (v6m.count("rfc4193")) nv6m["rfc4193"] = OSUtils::jsonBool(v6m["rfc4193"],false); + if (v6m.count("zt")) nv6m["zt"] = OSUtils::jsonBool(v6m["zt"],false); + if (v6m.count("6plane")) nv6m["6plane"] = OSUtils::jsonBool(v6m["6plane"],false); + } else { + nv6m["rfc4193"] = false; + nv6m["zt"] = false; + nv6m["6plane"] = false; + } + network["v6AssignMode"] = nv6m; + } + + if (b.count("routes")) { + json &rts = b["routes"]; + if (rts.is_array()) { + json nrts = json::array(); + for(unsigned long i=0;i().c_str()); + InetAddress v; + if (via.is_string()) v.fromString(via.get().c_str()); + if ( ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) && (t.netmaskBitsValid()) ) { + json tmp; + char tmp2[64]; + tmp["target"] = t.toString(tmp2); + if (v.ss_family == t.ss_family) + tmp["via"] = v.toIpString(tmp2); + else tmp["via"] = json(); + nrts.push_back(tmp); + if (nrts.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + } + } + } + network["routes"] = nrts; + } + } + + if (b.count("ipAssignmentPools")) { + json &ipp = b["ipAssignmentPools"]; + if (ipp.is_array()) { + json nipp = json::array(); + for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + } + } + network["ipAssignmentPools"] = nipp; + } + } + + if (b.count("rules")) { + json &rules = b["rules"]; + if (rules.is_array()) { + json nrules = json::array(); + for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + } + } + network["rules"] = nrules; + } + } + + if (b.count("authTokens")) { + json &authTokens = b["authTokens"]; + if (authTokens.is_object()) { + json nat; + for(json::iterator t(authTokens.begin());t!=authTokens.end();++t) { + if ((t.value().is_number())&&(t.value() >= 0)) + nat[t.key()] = t.value(); + } + network["authTokens"] = nat; + } else { + network["authTokens"] = {{}}; + } + } + + if (b.count("capabilities")) { + json &capabilities = b["capabilities"]; + if (capabilities.is_array()) { + std::map< uint64_t,json > ncaps; + for(unsigned long i=0;i= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + } + } + } + ncap["rules"] = nrules; + + ncaps[capId] = ncap; + } + } + + json ncapsa = json::array(); + for(std::map< uint64_t,json >::iterator c(ncaps.begin());c!=ncaps.end();++c) { + ncapsa.push_back(c->second); + if (ncapsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + network["capabilities"] = ncapsa; + } + } + + if (b.count("tags")) { + json &tags = b["tags"]; + if (tags.is_array()) { + std::map< uint64_t,json > ntags; + for(unsigned long i=0;i::iterator t(ntags.begin());t!=ntags.end();++t) { + ntagsa.push_back(t->second); + if (ntagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE) + break; + } + network["tags"] = ntagsa; + } + } + + } catch ( ... ) { + responseBody = "{ \"message\": \"exception occurred while parsing body variables\" }"; + responseContentType = "application/json"; + return 400; + } + + network["id"] = nwids; + network["nwid"] = nwids; // legacy + + DB::cleanNetwork(network); + _db.save(network,true); + + responseBody = OSUtils::jsonDump(network); + responseContentType = "application/json"; + return 200; + } // else 404 + + } // else 404 + + } + + return 404; +} + +unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE( + const std::vector &path, + const std::string &body, + std::string &responseBody, + std::string &responseContentType) +{ + if (path.empty()) + return 404; + + if (path[0] == "network") { + if ((path.size() >= 2)&&(path[1].length() == 16)) { + const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); + if (path.size() >= 3) { + if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) { + const uint64_t address = Utils::hexStrToU64(path[3].c_str()); + + json network,member; + _db.get(nwid,network,address,member); + _db.eraseMember(nwid, address); + + { + std::lock_guard l(_memberStatus_l); + _memberStatus.erase(_MemberStatusKey(nwid,address)); + } + + if (!member.size()) + return 404; + responseBody = OSUtils::jsonDump(member); + responseContentType = "application/json"; + return 200; + } + } else { + json network; + _db.get(nwid,network); + _db.eraseNetwork(nwid); + + { + std::lock_guard l(_memberStatus_l); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();) { + if (i->first.networkId == nwid) + _memberStatus.erase(i++); + else ++i; } } - if ((k.length() > 0)&&(v.length() > 0)) - d[k] = v; - } - } - const int64_t now = OSUtils::now(); - OSUtils::ztsnprintf(id,sizeof(id),"%.10llx-%.16llx-%.10llx-%.4x",_signingId.address().toInt(),now,rt.origin,(unsigned int)(idCounter++ & 0xffff)); - d["id"] = id; - d["objtype"] = "trace"; - d["ts"] = now; - d["nodeId"] = Utils::hex10(rt.origin,tmp); - _db.save(d,true); - } catch ( ... ) { - // drop invalid trace messages if an error occurs - } + if (!network.size()) + return 404; + responseBody = OSUtils::jsonDump(network); + responseContentType = "application/json"; + return 200; + } + } // else 404 + + } // else 404 + + return 404; } void EmbeddedNetworkController::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) @@ -1354,7 +1132,7 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const void *db,uint64_t ne void EmbeddedNetworkController::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) { const int64_t now = OSUtils::now(); - Revocation rev((uint32_t)_node->prng(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM); + Revocation rev((uint32_t)Utils::random(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM); rev.sign(_signingId); { std::lock_guard l(_memberStatus_l); @@ -1372,66 +1150,35 @@ void EmbeddedNetworkController::_request( const Identity &identity, const Dictionary &metaData) { - Metrics::network_config_request++; - auto tid = std::this_thread::get_id(); - std::stringstream ss; ss << tid; - std::string threadID = ss.str(); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - auto b1 = _member_status_lookup.Add({{"thread", threadID}}); - auto c1 = _member_status_lookup_count.Add({{"thread", threadID}}); - c1++; - b1.start(); -#endif - char nwids[24]; DB::NetworkSummaryInfo ns; json network,member; - if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) { + if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender)) return; - } const int64_t now = OSUtils::now(); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b1.stop(); - auto b2 = _node_is_online.Add({{"thread",threadID}}); - auto c2 = _node_is_online_count.Add({{"thread",threadID}}); - c2++; - b2.start(); -#endif - _db.nodeIsOnline(nwid,identity.address().toInt(),fromAddr); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b2.stop(); + if (requestPacketId) { + std::lock_guard l(_memberStatus_l); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; + if ((now - ms.lastRequestTime) <= ZT_NETCONF_MIN_REQUEST_PERIOD) + return; + ms.lastRequestTime = now; + } + + _db.nodeIsOnline(nwid,identity.address().toInt(),fromAddr); - auto b3 = _get_and_init_member.Add({{"thread", threadID}}); - auto c3 = _get_and_init_member_count.Add({{"thread",threadID}}); - c3++; - b3.start(); -#endif Utils::hex(nwid,nwids); _db.get(nwid,network,identity.address().toInt(),member,ns); - if ((!network.is_object())||(network.empty())) { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND, nullptr, 0); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b3.stop(); -#endif + if ((!network.is_object())||(network.size() == 0)) { + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND); return; } - const bool newMember = ((!member.is_object())||(member.empty())); + const bool newMember = ((!member.is_object())||(member.size() == 0)); DB::initMember(member); - _MemberStatusKey msk(nwid,identity.address().toInt()); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b3.stop(); -#endif { -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - auto b4 = _have_identity.Add({{"thread",threadID}}); - auto c4 = _have_identity_count.Add({{"thread",threadID}}); - c4++; - b4.start(); -#endif const std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); if (haveIdStr.length() > 0) { // If we already know this member's identity perform a full compare. This prevents @@ -1439,17 +1186,11 @@ void EmbeddedNetworkController::_request( // known member. try { if (Identity(haveIdStr.c_str()) != identity) { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED, nullptr, 0); - #ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b4.stop(); - #endif + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } } catch ( ... ) { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED, nullptr, 0); - #ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b4.stop(); - #endif + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } } else { @@ -1457,9 +1198,6 @@ void EmbeddedNetworkController::_request( char idtmp[1024]; member["identity"] = identity.toString(false,idtmp); } -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b4.stop(); -#endif } // These are always the same, but make sure they are set @@ -1472,12 +1210,6 @@ void EmbeddedNetworkController::_request( } // Determine whether and how member is authorized -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - auto b5 = _determine_auth.Add({{"thread",threadID}}); - auto c5 = _determine_auth_count.Add({{"thread",threadID}}); - c5++; - b5.start(); -#endif bool authorized = false; bool autoAuthorized = false; json autoAuthCredentialType,autoAuthCredential; @@ -1514,59 +1246,7 @@ void EmbeddedNetworkController::_request( member["lastAuthorizedCredentialType"] = autoAuthCredentialType; member["lastAuthorizedCredential"] = autoAuthCredential; } -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b5.stop(); -#endif - // Should we check SSO Stuff? - // If network is configured with SSO, and the member is not marked exempt: yes - // Otherwise no, we use standard auth logic. -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - auto b6 = _sso_check.Add({{"thread",threadID}}); - auto c6 = _sso_check_count.Add({{"thread",threadID}}); - c6++; - b6.start(); -#endif - AuthInfo info; - int64_t authenticationExpiryTime = -1; - bool networkSSOEnabled = OSUtils::jsonBool(network["ssoEnabled"], false); - bool memberSSOExempt = OSUtils::jsonBool(member["ssoExempt"], false); - if (networkSSOEnabled && !memberSSOExempt) { - authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0); - info = _db.getSSOAuthInfo(member, _ssoRedirectURL); - assert(info.enabled == networkSSOEnabled); - if (authenticationExpiryTime <= now) { - if (info.version == 0) { - Dictionary<4096> authInfo; - authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, (uint64_t)0ULL); - authInfo.add(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, info.authenticationURL.c_str()); - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes()); - } else if (info.version == 1) { - Dictionary<8192> authInfo; - authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, info.version); - authInfo.add(ZT_AUTHINFO_DICT_KEY_ISSUER_URL, info.issuerURL.c_str()); - authInfo.add(ZT_AUTHINFO_DICT_KEY_CENTRAL_ENDPOINT_URL, info.centralAuthURL.c_str()); - authInfo.add(ZT_AUTHINFO_DICT_KEY_NONCE, info.ssoNonce.c_str()); - authInfo.add(ZT_AUTHINFO_DICT_KEY_STATE, info.ssoState.c_str()); - authInfo.add(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, info.ssoClientID.c_str()); - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes()); - } - DB::cleanMember(member); - _db.save(member,true); - #ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b6.stop(); - #endif - return; - } - } -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b6.stop(); - - auto b7 = _auth_check.Add({{"thread",threadID}}); - auto c7 = _auth_check_count.Add({{"thread",threadID}}); - c7++; - b7.start(); -#endif if (authorized) { // Update version info and meta-data if authorized and if this is a genuine request if (requestPacketId) { @@ -1582,8 +1262,8 @@ void EmbeddedNetworkController::_request( { std::lock_guard l(_memberStatus_l); - _MemberStatus &ms = _memberStatus[msk]; - ms.authenticationExpiryTime = authenticationExpiryTime; + _MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; + ms.vMajor = (int)vMajor; ms.vMinor = (int)vMinor; ms.vRev = (int)vRev; @@ -1591,43 +1271,31 @@ void EmbeddedNetworkController::_request( ms.lastRequestMetaData = metaData; ms.identity = identity; } - - if (authenticationExpiryTime > 0) { - std::lock_guard l(_expiringSoon_l); - _expiringSoon.insert(std::pair(authenticationExpiryTime, msk)); - } } } else { // If they are not authorized, STOP! DB::cleanMember(member); _db.save(member,true); - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED, nullptr, 0); - #ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b7.stop(); - #endif + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b7.stop(); -#endif // ------------------------------------------------------------------------- - // If we made it this far, they are authorized (and authenticated). + // If we made it this far, they are authorized. // ------------------------------------------------------------------------- - // Default timeout: 15 minutes. Maximum: two hours. Can be specified by an optional field in the network config - // if something longer than 15 minutes is desired. Minimum is 5 minutes since shorter than that would be flaky. -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - auto b8 = _json_schlep.Add({{"thread",threadID}}); - auto c8 = _json_schlep_count.Add({{"thread", threadID}}); - c8++; - b8.start(); -#endif - int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_DFL_MAX_DELTA; - if (network.contains("certificateTimeoutWindowSize")) { - credentialtmd = (int64_t)network["certificateTimeoutWindowSize"]; + int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + if (now > ns.mostRecentDeauthTime) { + // If we recently de-authorized a member, shrink credential TTL/max delta to + // be below the threshold required to exclude it. Cap this to a min/max to + // prevent jitter or absurdly large values. + const uint64_t deauthWindow = now - ns.mostRecentDeauthTime; + if (deauthWindow < ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA) { + credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA; + } else if (deauthWindow < (ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA + 5000ULL)) { + credentialtmd = deauthWindow - 5000ULL; + } } - credentialtmd = std::max(std::min(credentialtmd, ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA), ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA); std::unique_ptr nc(new NetworkConfig()); @@ -1642,40 +1310,6 @@ void EmbeddedNetworkController::_request( nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); - nc->ssoEnabled = networkSSOEnabled; //OSUtils::jsonBool(network["ssoEnabled"], false); - nc->ssoVersion = info.version; - - if (info.version == 0) { - nc->authenticationExpiryTime = OSUtils::jsonInt(member["authenticationExpiryTime"], 0LL); - if (!info.authenticationURL.empty()) { - Utils::scopy(nc->authenticationURL, sizeof(nc->authenticationURL), info.authenticationURL.c_str()); - } - } - else if (info.version == 1) { - nc->authenticationExpiryTime = OSUtils::jsonInt(member["authenticationExpiryTime"], 0LL); - if (!info.authenticationURL.empty()) { - Utils::scopy(nc->authenticationURL, sizeof(nc->authenticationURL), info.authenticationURL.c_str()); - } - if (!info.centralAuthURL.empty()) { - Utils::scopy(nc->centralAuthURL, sizeof(nc->centralAuthURL), info.centralAuthURL.c_str()); - } - if (!info.issuerURL.empty()) { - #ifdef ZT_DEBUG - fprintf(stderr, "copying issuerURL to nc: %s\n", info.issuerURL.c_str()); - #endif - Utils::scopy(nc->issuerURL, sizeof(nc->issuerURL), info.issuerURL.c_str()); - } - if (!info.ssoNonce.empty()) { - Utils::scopy(nc->ssoNonce, sizeof(nc->ssoNonce), info.ssoNonce.c_str()); - } - if (!info.ssoState.empty()) { - Utils::scopy(nc->ssoState, sizeof(nc->ssoState), info.ssoState.c_str()); - } - if (!info.ssoClientID.empty()) { - Utils::scopy(nc->ssoClientID, sizeof(nc->ssoClientID), info.ssoClientID.c_str()); - } - } - std::string rtt(OSUtils::jsonString(member["remoteTraceTarget"],"")); if (rtt.length() == 10) { nc->remoteTraceTarget = Address(Utils::hexStrToU64(rtt.c_str())); @@ -1690,9 +1324,8 @@ void EmbeddedNetworkController::_request( nc->remoteTraceLevel = (Trace::Level)OSUtils::jsonInt(network["remoteTraceLevel"],0ULL); } - for(std::vector
::const_iterator ab(ns.activeBridges.begin());ab!=ns.activeBridges.end();++ab) { + for(std::vector
::const_iterator ab(ns.activeBridges.begin());ab!=ns.activeBridges.end();++ab) nc->addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); - } json &v4AssignMode = network["v4AssignMode"]; json &v6AssignMode = network["v6AssignMode"]; @@ -1703,9 +1336,6 @@ void EmbeddedNetworkController::_request( json &tags = network["tags"]; json &memberCapabilities = member["capabilities"]; json &memberTags = member["tags"]; - json &dns = network["dns"]; - - //fprintf(stderr, "IP Assignment Pools for Network %s: %s\n", nwids, OSUtils::jsonDump(ipAssignmentPools, 2).c_str()); if (metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,0) <= 0) { // Old versions with no rules engine support get an allow everything rule. @@ -1751,11 +1381,11 @@ void EmbeddedNetworkController::_request( std::map< uint64_t,json * >::const_iterator ctmp = capsById.find(capId); if (ctmp != capsById.end()) { json *cap = ctmp->second; - if ((cap)&&(cap->is_object())&&(!cap->empty())) { + if ((cap)&&(cap->is_object())&&(cap->size() > 0)) { ZT_VirtualNetworkRule capr[ZT_MAX_CAPABILITY_RULES]; unsigned int caprc = 0; json &caprj = (*cap)["rules"]; - if ((caprj.is_array())&&(!caprj.empty())) { + if ((caprj.is_array())&&(caprj.size() > 0)) { for(unsigned long j=0;j= ZT_MAX_CAPABILITY_RULES) break; @@ -1821,7 +1451,7 @@ void EmbeddedNetworkController::_request( *(reinterpret_cast(&(r->target))) = t; if (v.ss_family == t.ss_family) *(reinterpret_cast(&(r->via))) = v; - ++nc->routeCount; + ++nc->routeCount; } } } @@ -1998,142 +1628,54 @@ void EmbeddedNetworkController::_request( } } } - - if(dns.is_object()) { - std::string domain = OSUtils::jsonString(dns["domain"],""); - memcpy(nc->dns.domain, domain.c_str(), domain.size()); - json &addrArray = dns["servers"]; - if (addrArray.is_array()) { - for(unsigned int j = 0; j < addrArray.size() && j < ZT_MAX_DNS_SERVERS; ++j) { - json &addr = addrArray[j]; - nc->dns.server_addr[j] = InetAddress(OSUtils::jsonString(addr,"").c_str()); - } - } - } else { - dns = json::object(); - } -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b8.stop(); -#endif // Issue a certificate of ownership for all static IPs -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - auto b9 = _issue_certificate.Add({{"thread",threadID}}); - auto c9 = _issue_certificate_count.Add({{"thread",threadID}}); - c9++; - b9.start(); -#endif if (nc->staticIpCount) { nc->certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1); - for(unsigned int i=0;istaticIpCount;++i) { + for(unsigned int i=0;istaticIpCount;++i) nc->certificatesOfOwnership[0].addThing(nc->staticIps[i]); - } nc->certificatesOfOwnership[0].sign(_signingId); nc->certificateOfOwnershipCount = 1; } - CertificateOfMembership com(now,credentialtmd,nwid,identity); + CertificateOfMembership com(now,credentialtmd,nwid,identity.address()); if (com.sign(_signingId)) { nc->com = com; } else { - _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR, nullptr, 0); - #ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b9.stop(); - #endif + _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR); return; } -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b9.stop(); - auto b10 = _save_member.Add({{"thread",threadID}}); - auto c10 = _save_member_count.Add({{"thread",threadID}}); - c10++; - b10.start(); -#endif DB::cleanMember(member); _db.save(member,true); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b10.stop(); - - auto b11 = _send_netconf.Add({{"thread",threadID}}); - auto c11 = _send_netconf_count.Add({{"thread",threadID}}); - c11++; - b11.start(); -#endif - _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - b11.stop(); -#endif + _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),false); } void EmbeddedNetworkController::_startThreads() { std::lock_guard l(_threads_l); - if (!_threads.empty()) { + if (!_threads.empty()) return; - } const long hwc = std::max((long)std::thread::hardware_concurrency(),(long)1); for(long t=0;t::STOP) { + if (!_queue.get(qe)) break; - } else if (timedWaitResult == BlockingQueue<_RQEntry *>::OK) { + try { if (qe) { - try { - _request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); - } catch (std::exception &e) { - fprintf(stderr,"ERROR: exception in controller request handling thread: %s" ZT_EOL_S,e.what()); - } catch ( ... ) { - fprintf(stderr,"ERROR: exception in controller request handling thread: unknown exception" ZT_EOL_S); - } + _request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData); delete qe; - qe = nullptr; } + } catch (std::exception &e) { + fprintf(stderr,"ERROR: exception in controller request handling thread: %s" ZT_EOL_S,e.what()); + } catch ( ... ) { + fprintf(stderr,"ERROR: exception in controller request handling thread: unknown exception" ZT_EOL_S); } } - Metrics::network_config_request_threads--; }); } } -void EmbeddedNetworkController::_ssoExpiryThread() { - while(_ssoExpiryRunning) { - std::vector<_MemberStatusKey> expired; - nlohmann::json network, member; - int64_t now = OSUtils::now(); - { - std::lock_guard l(_expiringSoon_l); - for(auto s=_expiringSoon.begin();s!=_expiringSoon.end();) { - Metrics::sso_expiration_checks++; - const int64_t when = s->first; - if (when <= now) { - // The user may have re-authorized, so we must actually look it up and check. - network.clear(); - member.clear(); - if (_db.get(s->second.networkId, network, s->second.nodeId, member)) { - int64_t authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0); - if (authenticationExpiryTime <= now) { - expired.push_back(s->second); - } - } - s = _expiringSoon.erase(s); - } else { - // Don't bother going further into the future than necessary. - break; - } - } - } - for(auto e=expired.begin();e!=expired.end();++e) { - Metrics::sso_member_deauth++; - onNetworkMemberDeauthorize(nullptr, e->networkId, e->nodeId); - } - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } -} - } // namespace ZeroTier diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index aa3f162f..82946940 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -35,9 +35,7 @@ #include "../osdep/Thread.hpp" #include "../osdep/BlockingQueue.hpp" -#include - -#include +#include "../ext/json/json.hpp" #include "DB.hpp" #include "DBMirrorSet.hpp" @@ -45,22 +43,22 @@ namespace ZeroTier { class Node; -struct RedisConfig; + +struct MQConfig; class EmbeddedNetworkController : public NetworkController,public DB::ChangeListener { public: /** * @param node Parent node + * @param ztPath ZeroTier base path * @param dbPath Database path (file path or database credentials) */ - EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, RedisConfig *rc); + EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc = NULL); virtual ~EmbeddedNetworkController(); virtual void init(const Identity &signingId,Sender *sender); - void setSSORedirectURL(const std::string &url); - virtual void request( uint64_t nwid, const InetAddress &fromAddr, @@ -68,12 +66,21 @@ public: const Identity &identity, const Dictionary &metaData); - void configureHTTPControlPlane( - httplib::Server &s, - httplib::Server &sV6, - const std::function); - - void handleRemoteTrace(const ZT_RemoteTrace &rt); + unsigned int handleControlPlaneHttpGET( + const std::vector &path, + const std::string &body, + std::string &responseBody, + std::string &responseContentType); + unsigned int handleControlPlaneHttpPOST( + const std::vector &path, + const std::string &body, + std::string &responseBody, + std::string &responseContentType); + unsigned int handleControlPlaneHttpDELETE( + const std::vector &path, + const std::string &body, + std::string &responseBody, + std::string &responseContentType); virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network); virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member); @@ -82,9 +89,6 @@ public: private: void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary &metaData); void _startThreads(); - void _ssoExpiryThread(); - - std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body); struct _RQEntry { @@ -97,7 +101,6 @@ private: RQENTRY_TYPE_REQUEST = 0 } type; }; - struct _MemberStatusKey { _MemberStatusKey() : networkId(0),nodeId(0) {} @@ -105,13 +108,11 @@ private: uint64_t networkId; uint64_t nodeId; inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); } - inline bool operator<(const _MemberStatusKey &k) const { return (k.networkId < networkId) || ((k.networkId == networkId)&&(k.nodeId < nodeId)); } }; struct _MemberStatus { - _MemberStatus() : lastRequestTime(0),authenticationExpiryTime(-1),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} - int64_t lastRequestTime; - int64_t authenticationExpiryTime; + _MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} + uint64_t lastRequestTime; int vMajor,vMinor,vRev,vProto; Dictionary lastRequestMetaData; Identity identity; @@ -143,39 +144,7 @@ private: std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus; std::mutex _memberStatus_l; - std::set< std::pair > _expiringSoon; - std::mutex _expiringSoon_l; - - RedisConfig *_rc; - std::string _ssoRedirectURL; - - bool _ssoExpiryRunning; - std::thread _ssoExpiry; - -#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK - prometheus::simpleapi::benchmark_family_t _member_status_lookup; - prometheus::simpleapi::counter_family_t _member_status_lookup_count; - prometheus::simpleapi::benchmark_family_t _node_is_online; - prometheus::simpleapi::counter_family_t _node_is_online_count; - prometheus::simpleapi::benchmark_family_t _get_and_init_member; - prometheus::simpleapi::counter_family_t _get_and_init_member_count; - prometheus::simpleapi::benchmark_family_t _have_identity; - prometheus::simpleapi::counter_family_t _have_identity_count; - prometheus::simpleapi::benchmark_family_t _determine_auth; - prometheus::simpleapi::counter_family_t _determine_auth_count; - prometheus::simpleapi::benchmark_family_t _sso_check; - prometheus::simpleapi::counter_family_t _sso_check_count; - prometheus::simpleapi::benchmark_family_t _auth_check; - prometheus::simpleapi::counter_family_t _auth_check_count; - prometheus::simpleapi::benchmark_family_t _json_schlep; - prometheus::simpleapi::counter_family_t _json_schlep_count; - prometheus::simpleapi::benchmark_family_t _issue_certificate; - prometheus::simpleapi::counter_family_t _issue_certificate_count; - prometheus::simpleapi::benchmark_family_t _save_member; - prometheus::simpleapi::counter_family_t _save_member_count; - prometheus::simpleapi::benchmark_family_t _send_netconf; - prometheus::simpleapi::counter_family_t _send_netconf_count; -#endif + MQConfig *_mqc; }; } // namespace ZeroTier diff --git a/controller/FileDB.cpp b/controller/FileDB.cpp index e410c156..0b360d88 100644 --- a/controller/FileDB.cpp +++ b/controller/FileDB.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -13,8 +13,6 @@ #include "FileDB.hpp" -#include "../node/Metrics.hpp" - namespace ZeroTier { @@ -22,13 +20,11 @@ FileDB::FileDB(const char *path) : DB(), _path(path), _networksPath(_path + ZT_PATH_SEPARATOR_S + "network"), - _tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"), _running(true) { OSUtils::mkdir(_path.c_str()); OSUtils::lockDownFile(_path.c_str(),true); OSUtils::mkdir(_networksPath.c_str()); - OSUtils::mkdir(_tracePath.c_str()); std::vector networks(OSUtils::listDirectory(_networksPath.c_str(),false)); std::string buf; @@ -41,7 +37,6 @@ FileDB::FileDB(const char *path) : if (nwids.length() == 16) { nlohmann::json nullJson; _networkChanged(nullJson,network,false); - Metrics::network_count++; std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member"); std::vector members(OSUtils::listDirectory(membersPath.c_str(),false)); for(auto m=members.begin();m!=members.end();++m) { @@ -53,7 +48,6 @@ FileDB::FileDB(const char *path) : if (addrs.length() == 10) { nlohmann::json nullJson2; _memberChanged(nullJson2,member,false); - Metrics::member_count++; } } catch ( ... ) {} } @@ -92,9 +86,8 @@ bool FileDB::save(nlohmann::json &record,bool notifyListeners) if ((!old.is_object())||(!_compareRecords(old,record))) { record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid); - if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) { + if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1); - } _networkChanged(old,record,notifyListeners); modified = true; } @@ -115,9 +108,8 @@ bool FileDB::save(nlohmann::json &record,bool notifyListeners) OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid); OSUtils::mkdir(p2); OSUtils::mkdir(pb); - if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) { + if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1); - } } _memberChanged(old,record,notifyListeners); modified = true; @@ -136,7 +128,7 @@ void FileDB::eraseNetwork(const uint64_t networkId) char p[16384]; OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId); OSUtils::rm(p); - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)networkId); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)networkId); OSUtils::rmDashRf(p); _networkChanged(network,nullJson,true); std::lock_guard l(this->_online_l); @@ -146,7 +138,8 @@ void FileDB::eraseNetwork(const uint64_t networkId) void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId) { nlohmann::json network,member,nullJson; - get(networkId,network,memberId,member); + get(networkId,network); + get(memberId,member); char p[4096]; OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json",_networksPath.c_str(),networkId,memberId); OSUtils::rm(p); diff --git a/controller/FileDB.hpp b/controller/FileDB.hpp index 4e1bbe09..82e634e6 100644 --- a/controller/FileDB.hpp +++ b/controller/FileDB.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -35,7 +35,6 @@ public: protected: std::string _path; std::string _networksPath; - std::string _tracePath; std::thread _onlineUpdateThread; std::map< uint64_t,std::map > > _online; std::mutex _online_l; diff --git a/controller/LFDB.cpp b/controller/LFDB.cpp index efccff65..d11b77a0 100644 --- a/controller/LFDB.cpp +++ b/controller/LFDB.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -48,7 +48,7 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons char maskingKey [128]; Utils::hex(sha512pk,32,maskingKey); - httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort); + httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort,600); int64_t timeRangeStart = 0; while (_running.load()) { { @@ -190,10 +190,10 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons if (resp) { if (resp->status == 200) { nlohmann::json results(OSUtils::jsonParse(resp->body)); - if ((results.is_array())&&(!results.empty())) { + if ((results.is_array())&&(results.size() > 0)) { for(std::size_t ri=0;ri 0)) { nlohmann::json &result = rset[0]; if (result.is_object()) { @@ -258,10 +258,10 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons if (resp) { if (resp->status == 200) { nlohmann::json results(OSUtils::jsonParse(resp->body)); - if ((results.is_array())&&(!results.empty())) { + if ((results.is_array())&&(results.size() > 0)) { for(std::size_t ri=0;ri 0)) { nlohmann::json &result = rset[0]; if (result.is_object()) { diff --git a/controller/LFDB.hpp b/controller/LFDB.hpp index 64933f7d..0849ae57 100644 --- a/controller/LFDB.hpp +++ b/controller/LFDB.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index e4a31ba2..08e06ee9 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -16,31 +16,23 @@ #ifdef ZT_CONTROLLER_USE_LIBPQ #include "../node/Constants.hpp" -#include "../node/SHA512.hpp" #include "EmbeddedNetworkController.hpp" +#include "RabbitMQ.hpp" #include "../version.h" -#include "Redis.hpp" - -#include #include #include -#include -#include -#include - - -// #define REDIS_TRACE 1 +#include +#include using json = nlohmann::json; namespace { -static const int DB_MINIMUM_VERSION = 38; +static const int DB_MINIMUM_VERSION = 5; static const char *_timestr() { - time_t t = time(0); char *ts = ctime(&t); char *p = ts; @@ -73,99 +65,12 @@ std::string join(const std::vector &elements, const char * const se } */ -std::vector split(std::string str, char delim){ - std::istringstream iss(str); - std::vector tokens; - std::string item; - while(std::getline(iss, item, delim)) { - tokens.push_back(item); - } - return tokens; -} - -std::string url_encode(const std::string &value) { - std::ostringstream escaped; - escaped.fill('0'); - escaped << std::hex; - - for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) { - std::string::value_type c = (*i); - - // Keep alphanumeric and other accepted characters intact - if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { - escaped << c; - continue; - } - - // Any other characters are percent-encoded - escaped << std::uppercase; - escaped << '%' << std::setw(2) << int((unsigned char) c); - escaped << std::nouppercase; - } - - return escaped.str(); -} - } // anonymous namespace using namespace ZeroTier; - -MemberNotificationReceiver::MemberNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel) - : pqxx::notification_receiver(c, channel) - , _psql(p) -{ - fprintf(stderr, "initialize MemberNotificationReceiver\n"); -} - - -void MemberNotificationReceiver::operator() (const std::string &payload, int packend_pid) { - fprintf(stderr, "Member Notification received: %s\n", payload.c_str()); - Metrics::pgsql_mem_notification++; - json tmp(json::parse(payload)); - 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()) { - _psql->_memberChanged(oldConfig,newConfig,(_psql->_ready>=2)); - fprintf(stderr, "payload sent\n"); - } -} - - -NetworkNotificationReceiver::NetworkNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel) - : pqxx::notification_receiver(c, channel) - , _psql(p) -{ - fprintf(stderr, "initialize NetworkNotificationReceiver\n"); -} - -void NetworkNotificationReceiver::operator() (const std::string &payload, int packend_pid) { - fprintf(stderr, "Network Notification received: %s\n", payload.c_str()); - Metrics::pgsql_net_notification++; - json tmp(json::parse(payload)); - 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()) { - _psql->_networkChanged(oldConfig,newConfig,(_psql->_ready>=2)); - fprintf(stderr, "payload sent\n"); - } -} - -using Attrs = std::vector>; -using Item = std::pair; -using ItemStream = std::vector; - - - -PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, RedisConfig *rc) +PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, MQConfig *mqc) : DB() - , _pool() , _myId(myId) , _myAddress(myId.address()) , _ready(0) @@ -173,79 +78,43 @@ PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, R , _run(1) , _waitNoticePrinted(false) , _listenPort(listenPort) - , _rc(rc) - , _redis(NULL) - , _cluster(NULL) - , _redisMemberStatus(false) - , _smee(NULL) + , _mqc(mqc) { char myAddress[64]; _myAddressStr = myId.address().toString(myAddress); - _connString = std::string(path); - auto f = std::make_shared(_connString); - _pool = std::make_shared >( - 15, 5, std::static_pointer_cast(f)); - - memset(_ssoPsk, 0, sizeof(_ssoPsk)); - char *const ssoPskHex = getenv("ZT_SSO_PSK"); -#ifdef ZT_TRACE - fprintf(stderr, "ZT_SSO_PSK: %s\n", ssoPskHex); -#endif - if (ssoPskHex) { - // SECURITY: note that ssoPskHex will always be null-terminated if libc actually - // returns something non-NULL. If the hex encodes something shorter than 48 bytes, - // it will be padded at the end with zeroes. If longer, it'll be truncated. - Utils::unhex(ssoPskHex, _ssoPsk, sizeof(_ssoPsk)); - } - const char *redisMemberStatus = getenv("ZT_REDIS_MEMBER_STATUS"); - if (redisMemberStatus && (strcmp(redisMemberStatus, "true") == 0)) { - _redisMemberStatus = true; - fprintf(stderr, "Using redis for member status\n"); + _connString = std::string(path) + " application_name=controller_" + _myAddressStr; + + // Database Schema Version Check + PGconn *conn = getPgConn(); + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn)); + exit(1); } - auto c = _pool->borrow(); - pqxx::work txn{*c->c}; + PGresult *res = PQexec(conn, "SELECT version FROM ztc_database"); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Error determining database version"); + exit(1); + } - pqxx::row r{txn.exec1("SELECT version FROM ztc_database")}; - int dbVersion = r[0].as(); - txn.commit(); + if (PQntuples(res) != 1) { + fprintf(stderr, "Invalid number of db version tuples returned."); + exit(1); + } + + int dbVersion = std::stoi(PQgetvalue(res, 0, 0)); if (dbVersion < DB_MINIMUM_VERSION) { fprintf(stderr, "Central database schema version too low. This controller version requires a minimum schema version of %d. Please upgrade your Central instance", DB_MINIMUM_VERSION); exit(1); } - _pool->unborrow(c); - if (_rc != NULL) { - sw::redis::ConnectionOptions opts; - sw::redis::ConnectionPoolOptions poolOpts; - opts.host = _rc->hostname; - opts.port = _rc->port; - opts.password = _rc->password; - opts.db = 0; - opts.keep_alive = true; - opts.connect_timeout = std::chrono::seconds(3); - poolOpts.size = 25; - poolOpts.wait_timeout = std::chrono::seconds(5); - poolOpts.connection_lifetime = std::chrono::minutes(3); - poolOpts.connection_idle_time = std::chrono::minutes(1); - if (_rc->clusterMode) { - fprintf(stderr, "Using Redis in Cluster Mode\n"); - _cluster = std::make_shared(opts, poolOpts); - } else { - fprintf(stderr, "Using Redis in Standalone Mode\n"); - _redis = std::make_shared(opts, poolOpts); - } - } + PQclear(res); + res = NULL; + PQfinish(conn); + conn = NULL; _readyLock.lock(); - - fprintf(stderr, "[%s] NOTICE: %.10llx controller PostgreSQL waiting for initial data download..." ZT_EOL_S, ::_timestr(), (unsigned long long)_myAddress.toInt()); - _waitNoticePrinted = true; - - initializeNetworks(); - initializeMembers(); - _heartbeatThread = std::thread(&PostgreSQL::heartbeat, this); _membersDbWatcher = std::thread(&PostgreSQL::membersDbWatcher, this); _networksDbWatcher = std::thread(&PostgreSQL::networksDbWatcher, this); @@ -253,59 +122,31 @@ PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, R _commitThread[i] = std::thread(&PostgreSQL::commitThread, this); } _onlineNotificationThread = std::thread(&PostgreSQL::onlineNotificationThread, this); - - configureSmee(); } PostgreSQL::~PostgreSQL() { - if (_smee != NULL) { - smeeclient::smee_client_delete(_smee); - _smee = NULL; - } - _run = 0; std::this_thread::sleep_for(std::chrono::milliseconds(100)); _heartbeatThread.join(); _membersDbWatcher.join(); _networksDbWatcher.join(); - _commitQueue.stop(); for (int i = 0; i < ZT_CENTRAL_CONTROLLER_COMMIT_THREADS; ++i) { _commitThread[i].join(); } _onlineNotificationThread.join(); + } -void PostgreSQL::configureSmee() -{ - const char *TEMPORAL_SCHEME = "ZT_TEMPORAL_SCHEME"; - const char *TEMPORAL_HOST = "ZT_TEMPORAL_HOST"; - const char *TEMPORAL_PORT = "ZT_TEMPORAL_PORT"; - const char *TEMPORAL_NAMESPACE = "ZT_TEMPORAL_NAMESPACE"; - const char *SMEE_TASK_QUEUE = "ZT_SMEE_TASK_QUEUE"; - - const char *scheme = getenv(TEMPORAL_SCHEME); - if (scheme == NULL) { - scheme = "http"; - } - const char *host = getenv(TEMPORAL_HOST); - const char *port = getenv(TEMPORAL_PORT); - const char *ns = getenv(TEMPORAL_NAMESPACE); - const char *task_queue = getenv(SMEE_TASK_QUEUE); - - if (scheme != NULL && host != NULL && port != NULL && ns != NULL && task_queue != NULL) { - fprintf(stderr, "creating smee client\n"); - std::string hostPort = std::string(scheme) + std::string("://") + std::string(host) + std::string(":") + std::string(port); - this->_smee = smeeclient::smee_client_new(hostPort.c_str(), ns, task_queue); - } else { - fprintf(stderr, "Smee client not configured\n"); - } -} bool PostgreSQL::waitForReady() { while (_ready < 2) { + if (!_waitNoticePrinted) { + _waitNoticePrinted = true; + fprintf(stderr, "[%s] NOTICE: %.10llx controller PostgreSQL waiting for initial data download..." ZT_EOL_S, ::_timestr(), (unsigned long long)_myAddress.toInt()); + } _readyLock.lock(); _readyLock.unlock(); } @@ -321,13 +162,10 @@ bool PostgreSQL::save(nlohmann::json &record,bool notifyListeners) { bool modified = false; try { - if (!record.is_object()) { - fprintf(stderr, "record is not an object?!?\n"); + if (!record.is_object()) return false; - } const std::string objtype = record["objtype"]; if (objtype == "network") { - //fprintf(stderr, "network save\n"); const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL); if (nwid) { nlohmann::json old; @@ -339,25 +177,17 @@ bool PostgreSQL::save(nlohmann::json &record,bool notifyListeners) } } } else if (objtype == "member") { - std::string networkId = record["nwid"]; - std::string memberId = record["id"]; const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL); const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL); - //fprintf(stderr, "member save %s-%s\n", networkId.c_str(), memberId.c_str()); if ((id)&&(nwid)) { nlohmann::json network,old; get(nwid,network,id,old); if ((!old.is_object())||(!_compareRecords(old,record))) { - //fprintf(stderr, "commit queue post\n"); record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL; _commitQueue.post(std::pair(record,notifyListeners)); modified = true; - } else { - //fprintf(stderr, "no change\n"); } } - } else { - fprintf(stderr, "uhh waaat\n"); } } catch (std::exception &e) { fprintf(stderr, "Error on PostgreSQL::save: %s\n", e.what()); @@ -369,7 +199,6 @@ bool PostgreSQL::save(nlohmann::json &record,bool notifyListeners) void PostgreSQL::eraseNetwork(const uint64_t networkId) { - fprintf(stderr, "PostgreSQL::eraseNetwork\n"); char tmp2[24]; waitForReady(); Utils::hex(networkId, tmp2); @@ -378,16 +207,12 @@ void PostgreSQL::eraseNetwork(const uint64_t networkId) tmp.first["objtype"] = "_delete_network"; tmp.second = true; _commitQueue.post(tmp); - nlohmann::json nullJson; - _networkChanged(tmp.first, nullJson, true); } void PostgreSQL::eraseMember(const uint64_t networkId, const uint64_t memberId) { - fprintf(stderr, "PostgreSQL::eraseMember\n"); char tmp2[24]; - waitForReady(); - std::pair tmp, nw; + std::pair tmp; Utils::hex(networkId, tmp2); tmp.first["nwid"] = tmp2; Utils::hex(memberId, tmp2); @@ -395,8 +220,6 @@ void PostgreSQL::eraseMember(const uint64_t networkId, const uint64_t memberId) tmp.first["objtype"] = "_delete_member"; tmp.second = true; _commitQueue.post(tmp); - nlohmann::json nullJson; - _memberChanged(tmp.first, nullJson, true); } void PostgreSQL::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress) @@ -409,642 +232,311 @@ void PostgreSQL::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, } } -AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) -{ - Metrics::db_get_sso_info++; - // NONCE is just a random character string. no semantic meaning - // state = HMAC SHA384 of Nonce based on shared sso key - // - // need nonce timeout in database? make sure it's used within X time - // X is 5 minutes for now. Make configurable later? - // - // how do we tell when a nonce is used? if auth_expiration_time is set - std::string networkId = member["nwid"]; - std::string memberId = member["id"]; - - - char authenticationURL[4096] = {0}; - AuthInfo info; - info.enabled = true; - - //if (memberId == "a10dccea52" && networkId == "8056c2e21c24673d") { - // fprintf(stderr, "invalid authinfo for grant's machine\n"); - // info.version=1; - // return info; - //} - // fprintf(stderr, "PostgreSQL::updateMemberOnLoad: %s-%s\n", networkId.c_str(), memberId.c_str()); - std::shared_ptr c; - try { - c = _pool->borrow(); - pqxx::work w(*c->c); - - char nonceBytes[16] = {0}; - std::string nonce = ""; - - // check if the member exists first. - pqxx::row count = w.exec_params1("SELECT count(id) FROM ztc_member WHERE id = $1 AND network_id = $2 AND deleted = false", memberId, networkId); - if (count[0].as() == 1) { - // get active nonce, if exists. - pqxx::result r = w.exec_params("SELECT nonce FROM ztc_sso_expiry " - "WHERE network_id = $1 AND member_id = $2 " - "AND ((NOW() AT TIME ZONE 'UTC') <= authentication_expiry_time) AND ((NOW() AT TIME ZONE 'UTC') <= nonce_expiration)", - networkId, memberId); - - if (r.size() == 0) { - // no active nonce. - // find an unused nonce, if one exists. - pqxx::result r = w.exec_params("SELECT nonce FROM ztc_sso_expiry " - "WHERE network_id = $1 AND member_id = $2 " - "AND authentication_expiry_time IS NULL AND ((NOW() AT TIME ZONE 'UTC') <= nonce_expiration)", - networkId, memberId); - - if (r.size() == 1) { - // we have an existing nonce. Use it - nonce = r.at(0)[0].as(); - Utils::unhex(nonce.c_str(), nonceBytes, sizeof(nonceBytes)); - } else if (r.empty()) { - // create a nonce - Utils::getSecureRandom(nonceBytes, 16); - char nonceBuf[64] = {0}; - Utils::hex(nonceBytes, sizeof(nonceBytes), nonceBuf); - nonce = std::string(nonceBuf); - - pqxx::result ir = w.exec_params0("INSERT INTO ztc_sso_expiry " - "(nonce, nonce_expiration, network_id, member_id) VALUES " - "($1, TO_TIMESTAMP($2::double precision/1000), $3, $4)", - nonce, OSUtils::now() + 300000, networkId, memberId); - - w.commit(); - } else { - // > 1 ?!? Thats an error! - fprintf(stderr, "> 1 unused nonce!\n"); - exit(6); - } - } else if (r.size() == 1) { - nonce = r.at(0)[0].as(); - Utils::unhex(nonce.c_str(), nonceBytes, sizeof(nonceBytes)); - } else { - // more than 1 nonce in use? Uhhh... - fprintf(stderr, "> 1 nonce in use for network member?!?\n"); - exit(7); - } - - r = w.exec_params( - "SELECT oc.client_id, oc.authorization_endpoint, oc.issuer, oc.provider, oc.sso_impl_version " - "FROM ztc_network AS n " - "INNER JOIN ztc_org o " - " ON o.owner_id = n.owner_id " - "LEFT OUTER JOIN ztc_network_oidc_config noc " - " ON noc.network_id = n.id " - "LEFT OUTER JOIN ztc_oidc_config oc " - " ON noc.client_id = oc.client_id AND oc.org_id = o.org_id " - "WHERE n.id = $1 AND n.sso_enabled = true", networkId); - - std::string client_id = ""; - std::string authorization_endpoint = ""; - std::string issuer = ""; - std::string provider = ""; - uint64_t sso_version = 0; - - if (r.size() == 1) { - client_id = r.at(0)[0].as>().value_or(""); - authorization_endpoint = r.at(0)[1].as>().value_or(""); - issuer = r.at(0)[2].as>().value_or(""); - provider = r.at(0)[3].as>().value_or(""); - sso_version = r.at(0)[4].as>().value_or(1); - } else if (r.size() > 1) { - fprintf(stderr, "ERROR: More than one auth endpoint for an organization?!?!? NetworkID: %s\n", networkId.c_str()); - } else { - fprintf(stderr, "No client or auth endpoint?!?\n"); - } - - info.version = sso_version; - - // no catch all else because we don't actually care if no records exist here. just continue as normal. - if ((!client_id.empty())&&(!authorization_endpoint.empty())) { - - uint8_t state[48]; - HMACSHA384(_ssoPsk, nonceBytes, sizeof(nonceBytes), state); - char state_hex[256]; - Utils::hex(state, 48, state_hex); - - if (info.version == 0) { - char url[2048] = {0}; - OSUtils::ztsnprintf(url, sizeof(authenticationURL), - "%s?response_type=id_token&response_mode=form_post&scope=openid+email+profile&redirect_uri=%s&nonce=%s&state=%s&client_id=%s", - authorization_endpoint.c_str(), - url_encode(redirectURL).c_str(), - nonce.c_str(), - state_hex, - client_id.c_str()); - info.authenticationURL = std::string(url); - } else if (info.version == 1) { - info.ssoClientID = client_id; - info.issuerURL = issuer; - info.ssoProvider = provider; - info.ssoNonce = nonce; - info.ssoState = std::string(state_hex) + "_" +networkId; - info.centralAuthURL = redirectURL; -#ifdef ZT_DEBUG - fprintf( - stderr, - "ssoClientID: %s\nissuerURL: %s\nssoNonce: %s\nssoState: %s\ncentralAuthURL: %s\nprovider: %s\n", - info.ssoClientID.c_str(), - info.issuerURL.c_str(), - info.ssoNonce.c_str(), - info.ssoState.c_str(), - info.centralAuthURL.c_str(), - provider.c_str()); -#endif - } - } else { - fprintf(stderr, "client_id: %s\nauthorization_endpoint: %s\n", client_id.c_str(), authorization_endpoint.c_str()); - } - } - - _pool->unborrow(c); - } catch (std::exception &e) { - fprintf(stderr, "ERROR: Error updating member on load for network %s: %s\n", networkId.c_str(), e.what()); - } - - return info; //std::string(authenticationURL); -} - -void PostgreSQL::initializeNetworks() +void PostgreSQL::initializeNetworks(PGconn *conn) { try { - std::string setKey = "networks:{" + _myAddressStr + "}"; - - fprintf(stderr, "Initializing Networks...\n"); - - if (_redisMemberStatus) { - fprintf(stderr, "Init Redis for networks...\n"); - try { - if (_rc->clusterMode) { - _cluster->del(setKey); - } else { - _redis->del(setKey); - } - } catch (sw::redis::Error &e) { - // ignore. if this key doesn't exist, there's no reason to delete it - } + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn)); + exit(1); } - std::unordered_set networkSet; + const char *params[1] = { + _myAddressStr.c_str() + }; - char qbuf[2048] = {0}; - sprintf(qbuf, - "SELECT n.id, (EXTRACT(EPOCH FROM n.creation_time AT TIME ZONE 'UTC')*1000)::bigint as creation_time, n.capabilities, " - "n.enable_broadcast, (EXTRACT(EPOCH FROM n.last_modified AT TIME ZONE 'UTC')*1000)::bigint AS last_modified, n.mtu, n.multicast_limit, n.name, n.private, n.remote_trace_level, " - "n.remote_trace_target, n.revision, n.rules, n.tags, n.v4_assign_mode, n.v6_assign_mode, n.sso_enabled, (CASE WHEN n.sso_enabled THEN noc.client_id ELSE NULL END) as client_id, " - "(CASE WHEN n.sso_enabled THEN oc.authorization_endpoint ELSE NULL END) as authorization_endpoint, " - "(CASE WHEN n.sso_enabled THEN oc.provider ELSE NULL END) as provider, d.domain, d.servers, " - "ARRAY(SELECT CONCAT(host(ip_range_start),'|', host(ip_range_end)) FROM ztc_network_assignment_pool WHERE network_id = n.id) AS assignment_pool, " - "ARRAY(SELECT CONCAT(host(address),'/',bits::text,'|',COALESCE(host(via), 'NULL'))FROM ztc_network_route WHERE network_id = n.id) AS routes " - "FROM ztc_network n " - "LEFT OUTER JOIN ztc_org o " - " ON o.owner_id = n.owner_id " - "LEFT OUTER JOIN ztc_network_oidc_config noc " - " ON noc.network_id = n.id " - "LEFT OUTER JOIN ztc_oidc_config oc " - " ON noc.client_id = oc.client_id AND oc.org_id = o.org_id " - "LEFT OUTER JOIN ztc_network_dns d " - " ON d.network_id = n.id " - "WHERE deleted = false AND controller_id = '%s'", _myAddressStr.c_str()); - auto c = _pool->borrow(); - auto c2 = _pool->borrow(); - pqxx::work w{*c->c}; + PGresult *res = PQexecParams(conn, "SELECT id, EXTRACT(EPOCH FROM creation_time AT TIME ZONE 'UTC')*1000, capabilities, " + "enable_broadcast, EXTRACT(EPOCH FROM last_modified AT TIME ZONE 'UTC')*1000, mtu, multicast_limit, name, private, remote_trace_level, " + "remote_trace_target, revision, rules, tags, v4_assign_mode, v6_assign_mode FROM ztc_network " + "WHERE deleted = false AND controller_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); - fprintf(stderr, "Load networks from psql...\n"); - auto stream = pqxx::stream_from::query(w, qbuf); - - std::tuple< - std::string // network ID - , std::optional // creationTime - , std::optional // capabilities - , std::optional // enableBroadcast - , std::optional // lastModified - , std::optional // mtu - , std::optional // multicastLimit - , std::optional // name - , bool // private - , std::optional // remoteTraceLevel - , std::optional // remoteTraceTarget - , std::optional // revision - , std::optional // rules - , std::optional // tags - , std::optional // v4AssignMode - , std::optional // v6AssignMode - , std::optional // ssoEnabled - , std::optional // clientId - , std::optional // authorizationEndpoint - , std::optional // ssoProvider - , std::optional // domain - , std::optional // servers - , std::string // assignmentPoolString - , std::string // routeString - > row; - - uint64_t count = 0; - auto tmp = std::chrono::high_resolution_clock::now(); - uint64_t total = 0; - while (stream >> row) { - auto start = std::chrono::high_resolution_clock::now(); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Networks Initialization Failed: %s", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } + int numRows = PQntuples(res); + for (int i = 0; i < numRows; ++i) { json empty; json config; - initNetwork(config); + const char *nwidparam[1] = { + PQgetvalue(res, i, 0) + }; - std::string nwid = std::get<0>(row); - std::optional creationTime = std::get<1>(row); - std::optional capabilities = std::get<2>(row); - std::optional enableBroadcast = std::get<3>(row); - std::optional lastModified = std::get<4>(row); - std::optional mtu = std::get<5>(row); - std::optional multicastLimit = std::get<6>(row); - std::optional name = std::get<7>(row); - bool isPrivate = std::get<8>(row); - std::optional remoteTraceLevel = std::get<9>(row); - std::optional remoteTraceTarget = std::get<10>(row); - std::optional revision = std::get<11>(row); - std::optional rules = std::get<12>(row); - std::optional tags = std::get<13>(row); - std::optional v4AssignMode = std::get<14>(row); - std::optional v6AssignMode = std::get<15>(row); - std::optional ssoEnabled = std::get<16>(row); - std::optional clientId = std::get<17>(row); - std::optional authorizationEndpoint = std::get<18>(row); - std::optional ssoProvider = std::get<19>(row); - std::optional dnsDomain = std::get<20>(row); - std::optional dnsServers = std::get<21>(row); - std::string assignmentPoolString = std::get<22>(row); - std::string routesString = std::get<23>(row); - - config["id"] = nwid; - config["nwid"] = nwid; - config["creationTime"] = creationTime.value_or(0); - config["capabilities"] = json::parse(capabilities.value_or("[]")); - config["enableBroadcast"] = enableBroadcast.value_or(false); - config["lastModified"] = lastModified.value_or(0); - config["mtu"] = mtu.value_or(2800); - config["multicastLimit"] = multicastLimit.value_or(64); - config["name"] = name.value_or(""); - config["private"] = isPrivate; - config["remoteTraceLevel"] = remoteTraceLevel.value_or(0); - config["remoteTraceTarget"] = remoteTraceTarget.value_or(""); - config["revision"] = revision.value_or(0); - config["rules"] = json::parse(rules.value_or("[]")); - config["tags"] = json::parse(tags.value_or("[]")); - config["v4AssignMode"] = json::parse(v4AssignMode.value_or("{}")); - config["v6AssignMode"] = json::parse(v6AssignMode.value_or("{}")); - config["ssoEnabled"] = ssoEnabled.value_or(false); - config["objtype"] = "network"; - config["ipAssignmentPools"] = json::array(); - config["routes"] = json::array(); - config["clientId"] = clientId.value_or(""); - config["authorizationEndpoint"] = authorizationEndpoint.value_or(""); - config["provider"] = ssoProvider.value_or(""); - - networkSet.insert(nwid); - - if (dnsDomain.has_value()) { - std::string serverList = dnsServers.value(); - json obj; - auto servers = json::array(); - if (serverList.rfind("{",0) != std::string::npos) { - serverList = serverList.substr(1, serverList.size()-2); - std::stringstream ss(serverList); - while(ss.good()) { - std::string server; - std::getline(ss, server, ','); - servers.push_back(server); - } - } - obj["domain"] = dnsDomain.value(); - obj["servers"] = servers; - config["dns"] = obj; + config["id"] = PQgetvalue(res, i, 0); + config["nwid"] = PQgetvalue(res, i, 0); + try { + config["creationTime"] = std::stoull(PQgetvalue(res, i, 1)); + } catch (std::exception &e) { + config["creationTime"] = 0ULL; + //fprintf(stderr, "Error converting creation time: %s\n", PQgetvalue(res, i, 1)); } - - config["ipAssignmentPools"] = json::array(); - if (assignmentPoolString != "{}") { - std::string tmp = assignmentPoolString.substr(1, assignmentPoolString.size()-2); - std::vector assignmentPools = split(tmp, ','); - for (auto it = assignmentPools.begin(); it != assignmentPools.end(); ++it) { - std::vector r = split(*it, '|'); - json ip; - ip["ipRangeStart"] = r[0]; - ip["ipRangeEnd"] = r[1]; - config["ipAssignmentPools"].push_back(ip); - } + config["capabilities"] = json::parse(PQgetvalue(res, i, 2)); + config["enableBroadcast"] = (strcmp(PQgetvalue(res, i, 3),"t")==0); + try { + config["lastModified"] = std::stoull(PQgetvalue(res, i, 4)); + } catch (std::exception &e) { + config["lastModified"] = 0ULL; + //fprintf(stderr, "Error converting last modified: %s\n", PQgetvalue(res, i, 4)); } - + try { + config["mtu"] = std::stoi(PQgetvalue(res, i, 5)); + } catch (std::exception &e) { + config["mtu"] = 2800; + } + try { + config["multicastLimit"] = std::stoi(PQgetvalue(res, i, 6)); + } catch (std::exception &e) { + config["multicastLimit"] = 64; + } + config["name"] = PQgetvalue(res, i, 7); + config["private"] = (strcmp(PQgetvalue(res, i, 8),"t")==0); + try { + config["remoteTraceLevel"] = std::stoi(PQgetvalue(res, i, 9)); + } catch (std::exception &e) { + config["remoteTraceLevel"] = 0; + } + config["remoteTraceTarget"] = PQgetvalue(res, i, 10); + try { + config["revision"] = std::stoull(PQgetvalue(res, i, 11)); + } catch (std::exception &e) { + config["revision"] = 0ULL; + //fprintf(stderr, "Error converting revision: %s\n", PQgetvalue(res, i, 11)); + } + config["rules"] = json::parse(PQgetvalue(res, i, 12)); + config["tags"] = json::parse(PQgetvalue(res, i, 13)); + config["v4AssignMode"] = json::parse(PQgetvalue(res, i, 14)); + config["v6AssignMode"] = json::parse(PQgetvalue(res, i, 15)); + config["objtype"] = "network"; + config["ipAssignmentPools"] = json::array(); config["routes"] = json::array(); - if (routesString != "{}") { - std::string tmp = routesString.substr(1, routesString.size()-2); - std::vector routes = split(tmp, ','); - for (auto it = routes.begin(); it != routes.end(); ++it) { - std::vector r = split(*it, '|'); - json route; - route["target"] = r[0]; - route["via"] = ((route["via"] == "NULL")? nullptr : r[1]); - config["routes"].push_back(route); - } + + PGresult *r2 = PQexecParams(conn, + "SELECT host(ip_range_start), host(ip_range_end) FROM ztc_network_assignment_pool WHERE network_id = $1", + 1, + NULL, + nwidparam, + NULL, + NULL, + 0); + + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "ERROR: Error retreiving IP pools for network: %s\n", PQresultErrorMessage(r2)); + PQclear(r2); + PQclear(res); + exit(1); } - Metrics::network_count++; + int n = PQntuples(r2); + for (int j = 0; j < n; ++j) { + json ip; + ip["ipRangeStart"] = PQgetvalue(r2, j, 0); + ip["ipRangeEnd"] = PQgetvalue(r2, j, 1); - _networkChanged(empty, config, false); - - auto end = std::chrono::high_resolution_clock::now(); - auto dur = std::chrono::duration_cast(end - start);; - total += dur.count(); - ++count; - if (count > 0 && count % 10000 == 0) { - fprintf(stderr, "Averaging %llu us per network\n", (total/count)); + config["ipAssignmentPools"].push_back(ip); } - } - if (count > 0) { - fprintf(stderr, "Took %llu us per network to load\n", (total/count)); - } - stream.complete(); + PQclear(r2); - w.commit(); - _pool->unborrow(c2); - _pool->unborrow(c); - fprintf(stderr, "done.\n"); + r2 = PQexecParams(conn, + "SELECT host(address), bits, host(via) FROM ztc_network_route WHERE network_id = $1", + 1, + NULL, + nwidparam, + NULL, + NULL, + 0); - if (!networkSet.empty()) { - if (_redisMemberStatus) { - fprintf(stderr, "adding networks to redis...\n"); - if (_rc->clusterMode) { - auto tx = _cluster->transaction(_myAddressStr, true, false); - uint64_t count = 0; - for (std::string nwid : networkSet) { - tx.sadd(setKey, nwid); - if (++count % 30000 == 0) { - tx.exec(); - tx = _cluster->transaction(_myAddressStr, true, false); - } - } - tx.exec(); + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "ERROR: Error retreiving routes for network: %s\n", PQresultErrorMessage(r2)); + PQclear(r2); + PQclear(res); + exit(1); + } + + n = PQntuples(r2); + for (int j = 0; j < n; ++j) { + std::string addr = PQgetvalue(r2, j, 0); + std::string bits = PQgetvalue(r2, j, 1); + std::string via = PQgetvalue(r2, j, 2); + json route; + route["target"] = addr + "/" + bits; + + if (via == "NULL") { + route["via"] = nullptr; } else { - auto tx = _redis->transaction(true, false); - uint64_t count = 0; - for (std::string nwid : networkSet) { - tx.sadd(setKey, nwid); - if (++count % 30000 == 0) { - tx.exec(); - tx = _redis->transaction(true, false); - } - } - tx.exec(); + route["via"] = via; } - fprintf(stderr, "done.\n"); + config["routes"].push_back(route); } + + PQclear(r2); + + _networkChanged(empty, config, false); } + PQclear(res); + if (++this->_ready == 2) { if (_waitNoticePrinted) { fprintf(stderr,"[%s] NOTICE: %.10llx controller PostgreSQL data download complete." ZT_EOL_S,_timestr(),(unsigned long long)_myAddress.toInt()); } _readyLock.unlock(); } - fprintf(stderr, "network init done.\n"); - } catch (sw::redis::Error &e) { - fprintf(stderr, "ERROR: Error initializing networks in Redis: %s\n", e.what()); - std::this_thread::sleep_for(std::chrono::milliseconds(5000)); - exit(-1); } catch (std::exception &e) { - fprintf(stderr, "ERROR: Error initializing networks: %s\n", e.what()); - std::this_thread::sleep_for(std::chrono::milliseconds(5000)); + fprintf(stderr, "ERROR: Error initializing networks: %s", e.what()); exit(-1); } } -void PostgreSQL::initializeMembers() +void PostgreSQL::initializeMembers(PGconn *conn) { - std::string memberId; - std::string networkId; try { - std::unordered_map networkMembers; - fprintf(stderr, "Initializing Members...\n"); - - std::string setKeyBase = "network-nodes-all:{" + _myAddressStr + "}:"; - - if (_redisMemberStatus) { - fprintf(stderr, "Initialize Redis for members...\n"); - std::unique_lock l(_networks_l); - std::unordered_set deletes; - for ( auto it : _networks) { - uint64_t nwid_i = it.first; - char nwidTmp[64] = {0}; - OSUtils::ztsnprintf(nwidTmp, sizeof(nwidTmp), "%.16llx", nwid_i); - std::string nwid(nwidTmp); - std::string key = setKeyBase + nwid; - deletes.insert(key); - } - - if (!deletes.empty()) { - try { - if (_rc->clusterMode) { - auto tx = _cluster->transaction(_myAddressStr, true, false); - for (std::string k : deletes) { - tx.del(k); - } - tx.exec(); - } else { - auto tx = _redis->transaction(true, false); - for (std::string k : deletes) { - tx.del(k); - } - tx.exec(); - } - } catch (sw::redis::Error &e) { - // ignore - } - } + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "Bad Database Connection: %s", PQerrorMessage(conn)); + exit(1); } - char qbuf[2048]; - sprintf(qbuf, - "SELECT m.id, m.network_id, m.active_bridge, m.authorized, m.capabilities, " - "(EXTRACT(EPOCH FROM m.creation_time AT TIME ZONE 'UTC')*1000)::bigint, m.identity, " - "(EXTRACT(EPOCH FROM m.last_authorized_time AT TIME ZONE 'UTC')*1000)::bigint, " - "(EXTRACT(EPOCH FROM m.last_deauthorized_time AT TIME ZONE 'UTC')*1000)::bigint, " - "m.remote_trace_level, m.remote_trace_target, m.tags, m.v_major, m.v_minor, m.v_rev, m.v_proto, " - "m.no_auto_assign_ips, m.revision, m.sso_exempt, " - "(CASE WHEN n.sso_enabled = TRUE AND m.sso_exempt = FALSE THEN " - " ( " - " SELECT (EXTRACT(EPOCH FROM e.authentication_expiry_time)*1000)::bigint " - " FROM ztc_sso_expiry e " - " INNER JOIN ztc_network n1 " - " ON n1.id = e.network_id AND n1.deleted = TRUE " - " WHERE e.network_id = m.network_id AND e.member_id = m.id AND n.sso_enabled = TRUE AND e.authentication_expiry_time IS NOT NULL " - " ORDER BY e.authentication_expiry_time DESC LIMIT 1 " - " ) " - " ELSE NULL " - " END) AS authentication_expiry_time, " - "ARRAY(SELECT DISTINCT address FROM ztc_member_ip_assignment WHERE member_id = m.id AND network_id = m.network_id) AS assigned_addresses " + const char *params[1] = { + _myAddressStr.c_str() + }; + + PGresult *res = PQexecParams(conn, + "SELECT m.id, m.network_id, m.active_bridge, m.authorized, m.capabilities, EXTRACT(EPOCH FROM m.creation_time AT TIME ZONE 'UTC')*1000, m.identity, " + " EXTRACT(EPOCH FROM m.last_authorized_time AT TIME ZONE 'UTC')*1000, " + " EXTRACT(EPOCH FROM m.last_deauthorized_time AT TIME ZONE 'UTC')*1000, " + " m.remote_trace_level, m.remote_trace_target, m.tags, m.v_major, m.v_minor, m.v_rev, m.v_proto, " + " m.no_auto_assign_ips, m.revision " "FROM ztc_member m " "INNER JOIN ztc_network n " " ON n.id = m.network_id " - "WHERE n.controller_id = '%s' AND n.deleted = FALSE AND m.deleted = FALSE", _myAddressStr.c_str()); - auto c = _pool->borrow(); - auto c2 = _pool->borrow(); - pqxx::work w{*c->c}; + "WHERE n.controller_id = $1 AND m.deleted = false", + 1, + NULL, + params, + NULL, + NULL, + 0); - fprintf(stderr, "Load members from psql...\n"); - auto stream = pqxx::stream_from::query(w, qbuf); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Member Initialization Failed: %s", PQerrorMessage(conn)); + PQclear(res); + exit(1); + } - std::tuple< - std::string // memberId - , std::string // memberId - , std::optional // activeBridge - , std::optional // authorized - , std::optional // capabilities - , std::optional // creationTime - , std::optional // identity - , std::optional // lastAuthorizedTime - , std::optional // lastDeauthorizedTime - , std::optional // remoteTraceLevel - , std::optional // remoteTraceTarget - , std::optional // tags - , std::optional // vMajor - , std::optional // vMinor - , std::optional // vRev - , std::optional // vProto - , std::optional // noAutoAssignIps - , std::optional // revision - , std::optional // ssoExempt - , std::optional // authenticationExpiryTime - , std::string // assignedAddresses - > row; - - uint64_t count = 0; - auto tmp = std::chrono::high_resolution_clock::now(); - uint64_t total = 0; - while (stream >> row) { - auto start = std::chrono::high_resolution_clock::now(); + int numRows = PQntuples(res); + for (int i = 0; i < numRows; ++i) { json empty; json config; - - initMember(config); - - memberId = std::get<0>(row); - networkId = std::get<1>(row); - std::optional activeBridge = std::get<2>(row); - std::optional authorized = std::get<3>(row); - std::optional capabilities = std::get<4>(row); - std::optional creationTime = std::get<5>(row); - std::optional identity = std::get<6>(row); - std::optional lastAuthorizedTime = std::get<7>(row); - std::optional lastDeauthorizedTime = std::get<8>(row); - std::optional remoteTraceLevel = std::get<9>(row); - std::optional remoteTraceTarget = std::get<10>(row); - std::optional tags = std::get<11>(row); - std::optional vMajor = std::get<12>(row); - std::optional vMinor = std::get<13>(row); - std::optional vRev = std::get<14>(row); - std::optional vProto = std::get<15>(row); - std::optional noAutoAssignIps = std::get<16>(row); - std::optional revision = std::get<17>(row); - std::optional ssoExempt = std::get<18>(row); - std::optional authenticationExpiryTime = std::get<19>(row); - std::string assignedAddresses = std::get<20>(row); - - networkMembers.insert(std::pair(setKeyBase+networkId, memberId)); + std::string memberId(PQgetvalue(res, i, 0)); + std::string networkId(PQgetvalue(res, i, 1)); + std::string ctime = PQgetvalue(res, i, 5); config["id"] = memberId; - config["address"] = memberId; config["nwid"] = networkId; - config["activeBridge"] = activeBridge.value_or(false); - config["authorized"] = authorized.value_or(false); - config["capabilities"] = json::parse(capabilities.value_or("[]")); - config["creationTime"] = creationTime.value_or(0); - config["identity"] = identity.value_or(""); - config["lastAuthorizedTime"] = lastAuthorizedTime.value_or(0); - config["lastDeauthorizedTime"] = lastDeauthorizedTime.value_or(0); - config["remoteTraceLevel"] = remoteTraceLevel.value_or(0); - config["remoteTraceTarget"] = remoteTraceTarget.value_or(""); - config["tags"] = json::parse(tags.value_or("[]")); - config["vMajor"] = vMajor.value_or(-1); - config["vMinor"] = vMinor.value_or(-1); - config["vRev"] = vRev.value_or(-1); - config["vProto"] = vProto.value_or(-1); - config["noAutoAssignIps"] = noAutoAssignIps.value_or(false); - config["revision"] = revision.value_or(0); - config["ssoExempt"] = ssoExempt.value_or(false); - config["authenticationExpiryTime"] = authenticationExpiryTime.value_or(0); + config["activeBridge"] = (strcmp(PQgetvalue(res, i, 2), "t") == 0); + config["authorized"] = (strcmp(PQgetvalue(res, i, 3), "t") == 0); + try { + config["capabilities"] = json::parse(PQgetvalue(res, i, 4)); + } catch (std::exception &e) { + config["capabilities"] = json::array(); + } + try { + config["creationTime"] = std::stoull(PQgetvalue(res, i, 5)); + } catch (std::exception &e) { + config["creationTime"] = 0ULL; + //fprintf(stderr, "Error upding creation time (member): %s\n", PQgetvalue(res, i, 5)); + } + config["identity"] = PQgetvalue(res, i, 6); + try { + config["lastAuthorizedTime"] = std::stoull(PQgetvalue(res, i, 7)); + } catch(std::exception &e) { + config["lastAuthorizedTime"] = 0ULL; + //fprintf(stderr, "Error updating last auth time (member): %s\n", PQgetvalue(res, i, 7)); + } + try { + config["lastDeauthorizedTime"] = std::stoull(PQgetvalue(res, i, 8)); + } catch( std::exception &e) { + config["lastDeauthorizedTime"] = 0ULL; + //fprintf(stderr, "Error updating last deauth time (member): %s\n", PQgetvalue(res, i, 8)); + } + try { + config["remoteTraceLevel"] = std::stoi(PQgetvalue(res, i, 9)); + } catch (std::exception &e) { + config["remoteTraceLevel"] = 0; + } + config["remoteTraceTarget"] = PQgetvalue(res, i, 10); + try { + config["tags"] = json::parse(PQgetvalue(res, i, 11)); + } catch (std::exception &e) { + config["tags"] = json::array(); + } + try { + config["vMajor"] = std::stoi(PQgetvalue(res, i, 12)); + } catch(std::exception &e) { + config["vMajor"] = -1; + } + try { + config["vMinor"] = std::stoi(PQgetvalue(res, i, 13)); + } catch (std::exception &e) { + config["vMinor"] = -1; + } + try { + config["vRev"] = std::stoi(PQgetvalue(res, i, 14)); + } catch (std::exception &e) { + config["vRev"] = -1; + } + try { + config["vProto"] = std::stoi(PQgetvalue(res, i, 15)); + } catch (std::exception &e) { + config["vProto"] = -1; + } + config["noAutoAssignIps"] = (strcmp(PQgetvalue(res, i, 16), "t") == 0); + try { + config["revision"] = std::stoull(PQgetvalue(res, i, 17)); + } catch (std::exception &e) { + config["revision"] = 0ULL; + //fprintf(stderr, "Error updating revision (member): %s\n", PQgetvalue(res, i, 17)); + } config["objtype"] = "member"; config["ipAssignments"] = json::array(); + const char *p2[2] = { + memberId.c_str(), + networkId.c_str() + }; - if (assignedAddresses != "{}") { - std::string tmp = assignedAddresses.substr(1, assignedAddresses.size()-2); - std::vector addrs = split(tmp, ','); - for (auto it = addrs.begin(); it != addrs.end(); ++it) { - config["ipAssignments"].push_back(*it); - } + PGresult *r2 = PQexecParams(conn, + "SELECT DISTINCT address FROM ztc_member_ip_assignment WHERE member_id = $1 AND network_id = $2", + 2, + NULL, + p2, + NULL, + NULL, + 0); + + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "Member Initialization Failed: %s", PQerrorMessage(conn)); + PQclear(r2); + PQclear(res); + exit(1); } - Metrics::member_count++; + int n = PQntuples(r2); + for (int j = 0; j < n; ++j) { + config["ipAssignments"].push_back(PQgetvalue(r2, j, 0)); + } _memberChanged(empty, config, false); - - memberId = ""; - networkId = ""; - - auto end = std::chrono::high_resolution_clock::now(); - auto dur = std::chrono::duration_cast(end - start); - total += dur.count(); - ++count; - if (count > 0 && count % 10000 == 0) { - fprintf(stderr, "Averaging %llu us per member\n", (total/count)); - } - } - if (count > 0) { - fprintf(stderr, "Took %llu us per member to load\n", (total/count)); } - stream.complete(); - - w.commit(); - _pool->unborrow(c2); - _pool->unborrow(c); - fprintf(stderr, "done.\n"); - - if (!networkMembers.empty()) { - if (_redisMemberStatus) { - fprintf(stderr, "Load member data into redis...\n"); - if (_rc->clusterMode) { - auto tx = _cluster->transaction(_myAddressStr, true, false); - uint64_t count = 0; - for (auto it : networkMembers) { - tx.sadd(it.first, it.second); - if (++count % 30000 == 0) { - tx.exec(); - tx = _cluster->transaction(_myAddressStr, true, false); - } - } - tx.exec(); - } else { - auto tx = _redis->transaction(true, false); - uint64_t count = 0; - for (auto it : networkMembers) { - tx.sadd(it.first, it.second); - if (++count % 30000 == 0) { - tx.exec(); - tx = _redis->transaction(true, false); - } - } - tx.exec(); - } - fprintf(stderr, "done.\n"); - } - } - - fprintf(stderr, "Done loading members...\n"); + PQclear(res); if (++this->_ready == 2) { if (_waitNoticePrinted) { @@ -1052,11 +544,8 @@ void PostgreSQL::initializeMembers() } _readyLock.unlock(); } - } catch (sw::redis::Error &e) { - fprintf(stderr, "ERROR: Error initializing members (redis): %s\n", e.what()); - exit(-1); } catch (std::exception &e) { - fprintf(stderr, "ERROR: Error initializing member: %s-%s %s\n", networkId.c_str(), memberId.c_str(), e.what()); + fprintf(stderr, "ERROR: Error initializing members: %s\n", e.what()); exit(-1); } } @@ -1080,65 +569,85 @@ void PostgreSQL::heartbeat() const char *publicIdentity = publicId; const char *hostname = hostnameTmp; + PGconn *conn = getPgConn(); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } while (_run == 1) { - // fprintf(stderr, "%s: heartbeat\n", controllerId); - auto c = _pool->borrow(); - int64_t ts = OSUtils::now(); - - if(c->c) { + if(PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "%s heartbeat thread lost connection to Database\n", _myAddressStr.c_str()); + PQfinish(conn); + exit(6); + } + if (conn) { std::string major = std::to_string(ZEROTIER_ONE_VERSION_MAJOR); std::string minor = std::to_string(ZEROTIER_ONE_VERSION_MINOR); std::string rev = std::to_string(ZEROTIER_ONE_VERSION_REVISION); std::string build = std::to_string(ZEROTIER_ONE_VERSION_BUILD); - std::string now = std::to_string(ts); + std::string now = std::to_string(OSUtils::now()); std::string host_port = std::to_string(_listenPort); - std::string use_redis = (_rc != NULL) ? "true" : "false"; - std::string redis_mem_status = (_redisMemberStatus) ? "true" : "false"; - - try { - pqxx::work w{*c->c}; + std::string use_rabbitmq = (_mqc != NULL) ? "true" : "false"; + const char *values[10] = { + controllerId, + hostname, + now.c_str(), + publicIdentity, + major.c_str(), + minor.c_str(), + rev.c_str(), + build.c_str(), + host_port.c_str(), + use_rabbitmq.c_str() + }; - pqxx::result res = - w.exec0("INSERT INTO ztc_controller (id, cluster_host, last_alive, public_identity, v_major, v_minor, v_rev, v_build, host_port, use_redis, redis_member_status) " - "VALUES ("+w.quote(controllerId)+", "+w.quote(hostname)+", TO_TIMESTAMP("+now+"::double precision/1000), "+ - w.quote(publicIdentity)+", "+major+", "+minor+", "+rev+", "+build+", "+host_port+", "+use_redis+", "+redis_mem_status+") " - "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, " - "v_rev = EXCLUDED.v_rev, v_build = EXCLUDED.v_rev, host_port = EXCLUDED.host_port, " - "use_redis = EXCLUDED.use_redis, redis_member_status = EXCLUDED.redis_member_status"); - w.commit(); - } catch (std::exception &e) { - fprintf(stderr, "%s: Heartbeat update failed: %s\n", controllerId, e.what()); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - continue; + 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) " + "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, " + "v_rev = EXCLUDED.v_rev, v_build = EXCLUDED.v_rev, host_port = EXCLUDED.host_port, " + "use_rabbitmq = EXCLUDED.use_rabbitmq", + 10, // number of parameters + NULL, // oid field. ignore + values, // values for substitution + NULL, // lengths in bytes of each value + NULL, // binary? + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "Heartbeat Update Failed: %s\n", PQresultErrorMessage(res)); } - - } - _pool->unborrow(c); - - try { - if (_redisMemberStatus) { - if (_rc->clusterMode) { - _cluster->zadd("controllers", "controllerId", ts); - } else { - _redis->zadd("controllers", "controllerId", ts); - } - } - } catch (sw::redis::Error &e) { - fprintf(stderr, "ERROR: Redis error in heartbeat thread: %s\n", e.what()); + PQclear(res); } std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } - fprintf(stderr, "Exited heartbeat thread\n"); + + PQfinish(conn); + conn = NULL; } void PostgreSQL::membersDbWatcher() { - if (_rc) { - _membersWatcher_Redis(); + PGconn *conn = getPgConn(NO_OVERRIDE); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + + initializeMembers(conn); + + if (this->_mqc != NULL) { + PQfinish(conn); + conn = NULL; + _membersWatcher_RabbitMQ(); } else { - _membersWatcher_Postgres(); + _membersWatcher_Postgres(conn); + PQfinish(conn); + conn = NULL; } if (_run == 1) { @@ -1148,366 +657,417 @@ void PostgreSQL::membersDbWatcher() fprintf(stderr, "Exited membersDbWatcher\n"); } -void PostgreSQL::_membersWatcher_Postgres() { - auto c = _pool->borrow(); +void PostgreSQL::_membersWatcher_Postgres(PGconn *conn) { + char buf[11] = {0}; + std::string cmd = "LISTEN member_" + std::string(_myAddress.toString(buf)); + PGresult *res = PQexec(conn, cmd.c_str()); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "LISTEN command failed: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQfinish(conn); + exit(1); + } - std::string stream = "member_" + _myAddressStr; - - fprintf(stderr, "Listening to member stream: %s\n", stream.c_str()); - MemberNotificationReceiver m(this, *c->c, stream); + PQclear(res); res = NULL; while(_run == 1) { - c->c->await_notification(5, 0); - } + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "ERROR: Member Watcher lost connection to Postgres."); + exit(-1); + } + PGnotify *notify = NULL; + PQconsumeInput(conn); + while ((notify = PQnotifies(conn)) != NULL) { + //fprintf(stderr, "ASYNC NOTIFY of '%s' id:%s received\n", notify->relname, notify->extra); - _pool->unborrow(c); + try { + json tmp(json::parse(notify->extra)); + 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 (...) {} // ignore bad records + + free(notify); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } } -void PostgreSQL::_membersWatcher_Redis() { +void PostgreSQL::_membersWatcher_RabbitMQ() { char buf[11] = {0}; - std::string key = "member-stream:{" + std::string(_myAddress.toString(buf)) + "}"; - std::string lastID = "0"; - fprintf(stderr, "Listening to member stream: %s\n", key.c_str()); + 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 { - json tmp; - std::unordered_map result; - if (_rc->clusterMode) { - _cluster->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end())); - } else { - _redis->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end())); + std::string msg = rmq.consume(); + // fprintf(stderr, "Got Member Update: %s\n", msg.c_str()); + if (msg.empty()) { + continue; } - if (!result.empty()) { - for (auto element : result) { - #ifdef REDIS_TRACE - fprintf(stdout, "Received notification from: %s\n", element.first.c_str()); - #endif - for (auto rec : element.second) { - std::string id = rec.first; - auto attrs = rec.second; - #ifdef REDIS_TRACE - fprintf(stdout, "Record ID: %s\n", id.c_str()); - fprintf(stdout, "attrs len: %lu\n", attrs.size()); - #endif - for (auto a : attrs) { - #ifdef REDIS_TRACE - fprintf(stdout, "key: %s\nvalue: %s\n", a.first.c_str(), a.second.c_str()); - #endif - try { - tmp = json::parse(a.second); - 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 (...) { - fprintf(stderr, "json parse error in _membersWatcher_Redis: %s\n", a.second.c_str()); - } - } - if (_rc->clusterMode) { - _cluster->xdel(key, id); - } else { - _redis->xdel(key, id); - } - lastID = id; - Metrics::redis_mem_notification++; - } - } + 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 (sw::redis::Error &e) { - fprintf(stderr, "Error in Redis members watcher: %s\n", e.what()); + } 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"); } } - fprintf(stderr, "membersWatcher ended\n"); } void PostgreSQL::networksDbWatcher() { - if (_rc) { - _networksWatcher_Redis(); + PGconn *conn = getPgConn(NO_OVERRIDE); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + + initializeNetworks(conn); + + if (this->_mqc != NULL) { + PQfinish(conn); + conn = NULL; + _networksWatcher_RabbitMQ(); } else { - _networksWatcher_Postgres(); + _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 networksDbWatcher\n"); + fprintf(stderr, "Exited membersDbWatcher\n"); } -void PostgreSQL::_networksWatcher_Postgres() { - std::string stream = "network_" + _myAddressStr; +void PostgreSQL::_networksWatcher_Postgres(PGconn *conn) { + char buf[11] = {0}; + std::string cmd = "LISTEN network_" + std::string(_myAddress.toString(buf)); + PGresult *res = PQexec(conn, cmd.c_str()); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "LISTEN command failed: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQfinish(conn); + exit(1); + } - fprintf(stderr, "Listening to member stream: %s\n", stream.c_str()); - - auto c = _pool->borrow(); - - NetworkNotificationReceiver n(this, *c->c, stream); + PQclear(res); res = NULL; while(_run == 1) { - c->c->await_notification(5,0); + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "ERROR: Network Watcher lost connection to Postgres."); + exit(-1); + } + PGnotify *notify = NULL; + PQconsumeInput(conn); + while ((notify = PQnotifies(conn)) != NULL) { + //fprintf(stderr, "ASYNC NOTIFY of '%s' id:%s received\n", notify->relname, notify->extra); + try { + json tmp(json::parse(notify->extra)); + 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 (...) {} // ignore bad records + free(notify); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } -void PostgreSQL::_networksWatcher_Redis() { +void PostgreSQL::_networksWatcher_RabbitMQ() { char buf[11] = {0}; - std::string key = "network-stream:{" + std::string(_myAddress.toString(buf)) + "}"; - std::string lastID = "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 { - json tmp; - std::unordered_map result; - if (_rc->clusterMode) { - _cluster->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end())); - } else { - _redis->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end())); + std::string msg = rmq.consume(); + if (msg.empty()) { + continue; } - - if (!result.empty()) { - for (auto element : result) { -#ifdef REDIS_TRACE - fprintf(stdout, "Received notification from: %s\n", element.first.c_str()); -#endif - for (auto rec : element.second) { - std::string id = rec.first; - auto attrs = rec.second; -#ifdef REDIS_TRACE - fprintf(stdout, "Record ID: %s\n", id.c_str()); - fprintf(stdout, "attrs len: %lu\n", attrs.size()); -#endif - for (auto a : attrs) { -#ifdef REDIS_TRACE - fprintf(stdout, "key: %s\nvalue: %s\n", a.first.c_str(), a.second.c_str()); -#endif - try { - tmp = json::parse(a.second); - 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::exception &e) { - fprintf(stderr, "json parse error in networkWatcher_Redis: what: %s json: %s\n", e.what(), a.second.c_str()); - } - } - if (_rc->clusterMode) { - _cluster->xdel(key, id); - } else { - _redis->xdel(key, id); - } - lastID = id; - } - Metrics::redis_net_notification++; - } + // 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 (sw::redis::Error &e) { - fprintf(stderr, "Error in Redis networks watcher: %s\n", e.what()); + } 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"); } } - fprintf(stderr, "networksWatcher ended\n"); } void PostgreSQL::commitThread() { - fprintf(stderr, "%s: commitThread start\n", _myAddressStr.c_str()); + PGconn *conn = getPgConn(); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "ERROR: Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } + std::pair qitem; while(_commitQueue.get(qitem)&(_run == 1)) { - //fprintf(stderr, "commitThread tick\n"); if (!qitem.first.is_object()) { - fprintf(stderr, "not an object\n"); continue; } - - std::shared_ptr c; + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "ERROR: Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); + } try { - c = _pool->borrow(); - } catch (std::exception &e) { - fprintf(stderr, "ERROR: %s\n", e.what()); - continue; - } - - if (!c) { - fprintf(stderr, "Error getting database connection\n"); - continue; - } - - Metrics::pgsql_commit_ticks++; - try { - nlohmann::json &config = (qitem.first); - const std::string objtype = config["objtype"]; + nlohmann::json *config = &(qitem.first); + const std::string objtype = (*config)["objtype"]; if (objtype == "member") { - // fprintf(stderr, "%s: commitThread: member\n", _myAddressStr.c_str()); - std::string memberId; - std::string networkId; try { - pqxx::work w(*c->c); - - memberId = config["id"]; - networkId = config["nwid"]; - + std::string memberId = (*config)["id"]; + std::string networkId = (*config)["nwid"]; + std::string identity = (*config)["identity"]; std::string target = "NULL"; - if (!config["remoteTraceTarget"].is_null()) { - target = config["remoteTraceTarget"]; - } - - pqxx::row nwrow = w.exec_params1("SELECT COUNT(id) FROM ztc_network WHERE id = $1", networkId); - int nwcount = nwrow[0].as(); - if (nwcount != 1) { - fprintf(stderr, "network %s does not exist. skipping member upsert\n", networkId.c_str()); - w.abort(); - _pool->unborrow(c); + if (!(*config)["remoteTraceTarget"].is_null()) { + target = (*config)["remoteTraceTarget"]; + } + + std::string caps = OSUtils::jsonDump((*config)["capabilities"], -1); + std::string lastAuthTime = std::to_string((long long)(*config)["lastAuthorizedTime"]); + std::string lastDeauthTime = std::to_string((long long)(*config)["lastDeauthorizedTime"]); + std::string rtraceLevel = std::to_string((int)(*config)["remoteTraceLevel"]); + std::string rev = std::to_string((unsigned long long)(*config)["revision"]); + std::string tags = OSUtils::jsonDump((*config)["tags"], -1); + std::string vmajor = std::to_string((int)(*config)["vMajor"]); + std::string vminor = std::to_string((int)(*config)["vMinor"]); + std::string vrev = std::to_string((int)(*config)["vRev"]); + std::string vproto = std::to_string((int)(*config)["vProto"]); + const char *values[19] = { + memberId.c_str(), + networkId.c_str(), + ((*config)["activeBridge"] ? "true" : "false"), + ((*config)["authorized"] ? "true" : "false"), + caps.c_str(), + identity.c_str(), + lastAuthTime.c_str(), + lastDeauthTime.c_str(), + ((*config)["noAutoAssignIps"] ? "true" : "false"), + rtraceLevel.c_str(), + (target == "NULL") ? NULL : target.c_str(), + rev.c_str(), + tags.c_str(), + vmajor.c_str(), + vminor.c_str(), + vrev.c_str(), + vproto.c_str() + }; + + PGresult *res = PQexecParams(conn, + "INSERT INTO ztc_member (id, network_id, active_bridge, authorized, capabilities, " + "identity, last_authorized_time, last_deauthorized_time, no_auto_assign_ips, " + "remote_trace_level, remote_trace_target, revision, tags, v_major, v_minor, v_rev, v_proto) " + "VALUES ($1, $2, $3, $4, $5, $6, " + "TO_TIMESTAMP($7::double precision/1000), TO_TIMESTAMP($8::double precision/1000), " + "$9, $10, $11, $12, $13, $14, $15, $16, $17) ON CONFLICT (network_id, id) DO UPDATE SET " + "active_bridge = EXCLUDED.active_bridge, authorized = EXCLUDED.authorized, capabilities = EXCLUDED.capabilities, " + "identity = EXCLUDED.identity, last_authorized_time = EXCLUDED.last_authorized_time, " + "last_deauthorized_time = EXCLUDED.last_deauthorized_time, no_auto_assign_ips = EXCLUDED.no_auto_assign_ips, " + "remote_trace_level = EXCLUDED.remote_trace_level, remote_trace_target = EXCLUDED.remote_trace_target, " + "revision = EXCLUDED.revision+1, tags = EXCLUDED.tags, v_major = EXCLUDED.v_major, " + "v_minor = EXCLUDED.v_minor, v_rev = EXCLUDED.v_rev, v_proto = EXCLUDED.v_proto", + 17, + NULL, + values, + 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()); + PQclear(res); + delete config; + config = nullptr; continue; } + PQclear(res); - pqxx::row mrow = w.exec_params1("SELECT COUNT(id) FROM ztc_member WHERE id = $1 AND network_id = $2", memberId, networkId); - int membercount = mrow[0].as(); - - bool isNewMember = false; - if (membercount == 0) { - // new member - isNewMember = true; - pqxx::result res = w.exec_params0( - "INSERT INTO ztc_member (id, network_id, active_bridge, authorized, capabilities, " - "identity, last_authorized_time, last_deauthorized_time, no_auto_assign_ips, " - "remote_trace_level, remote_trace_target, revision, tags, v_major, v_minor, v_rev, v_proto) " - "VALUES ($1, $2, $3, $4, $5, $6, " - "TO_TIMESTAMP($7::double precision/1000), TO_TIMESTAMP($8::double precision/1000), " - "$9, $10, $11, $12, $13, $14, $15, $16, $17)", - memberId, - networkId, - (bool)config["activeBridge"], - (bool)config["authorized"], - OSUtils::jsonDump(config["capabilities"], -1), - OSUtils::jsonString(config["identity"], ""), - (uint64_t)config["lastAuthorizedTime"], - (uint64_t)config["lastDeauthorizedTime"], - (bool)config["noAutoAssignIps"], - (int)config["remoteTraceLevel"], - target, - (uint64_t)config["revision"], - OSUtils::jsonDump(config["tags"], -1), - (int)config["vMajor"], - (int)config["vMinor"], - (int)config["vRev"], - (int)config["vProto"]); - } else { - // existing member - pqxx::result res = w.exec_params0( - "UPDATE ztc_member " - "SET active_bridge = $3, authorized = $4, capabilities = $5, identity = $6, " - "last_authorized_time = TO_TIMESTAMP($7::double precision/1000), " - "last_deauthorized_time = TO_TIMESTAMP($8::double precision/1000), " - "no_auto_assign_ips = $9, remote_trace_level = $10, remote_trace_target= $11, " - "revision = $12, tags = $13, v_major = $14, v_minor = $15, v_rev = $16, v_proto = $17 " - "WHERE id = $1 AND network_id = $2", - memberId, - networkId, - (bool)config["activeBridge"], - (bool)config["authorized"], - OSUtils::jsonDump(config["capabilities"], -1), - OSUtils::jsonString(config["identity"], ""), - (uint64_t)config["lastAuthorizedTime"], - (uint64_t)config["lastDeauthorizedTime"], - (bool)config["noAutoAssignIps"], - (int)config["remoteTraceLevel"], - target, - (uint64_t)config["revision"], - OSUtils::jsonDump(config["tags"], -1), - (int)config["vMajor"], - (int)config["vMinor"], - (int)config["vRev"], - (int)config["vProto"] - ); + res = PQexec(conn, "BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error beginning transaction: %s\n", PQresultErrorMessage(res)); + PQclear(res); + delete config; + config = nullptr; + continue; } - if (!isNewMember) { - pqxx::result res = w.exec_params0("DELETE FROM ztc_member_ip_assignment WHERE member_id = $1 AND network_id = $2", - memberId, networkId); + PQclear(res); + + const char *v2[2] = { + memberId.c_str(), + networkId.c_str() + }; + + res = PQexecParams(conn, + "DELETE FROM ztc_member_ip_assignment WHERE member_id = $1 AND network_id = $2", + 2, + NULL, + v2, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating IP address assignments: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK"));; + delete config; + config = nullptr; + continue; } + PQclear(res); + std::vector assignments; - bool ipAssignError = false; - for (auto i = config["ipAssignments"].begin(); i != config["ipAssignments"].end(); ++i) { + for (auto i = (*config)["ipAssignments"].begin(); i != (*config)["ipAssignments"].end(); ++i) { std::string addr = *i; if (std::find(assignments.begin(), assignments.end(), addr) != assignments.end()) { continue; } - pqxx::result res = w.exec_params0( - "INSERT INTO ztc_member_ip_assignment (member_id, network_id, address) VALUES ($1, $2, $3) ON CONFLICT (network_id, member_id, address) DO NOTHING", - memberId, networkId, addr); + const char *v3[3] = { + memberId.c_str(), + networkId.c_str(), + addr.c_str() + }; - assignments.push_back(addr); - } - if (ipAssignError) { - fprintf(stderr, "%s: ipAssignError\n", _myAddressStr.c_str()); - w.abort(); - _pool->unborrow(c); - c.reset(); - continue; - } + res = PQexecParams(conn, + "INSERT INTO ztc_member_ip_assignment (member_id, network_id, address) VALUES ($1, $2, $3)", + 3, + NULL, + v3, + NULL, + NULL, + 0); - w.commit(); - - if (_smee != NULL && isNewMember) { - pqxx::row row = w.exec_params1( - "SELECT " - " count(h.hook_id) " - "FROM " - " ztc_hook h " - " INNER JOIN ztc_org o ON o.org_id = h.org_id " - " INNER JOIN ztc_network n ON n.owner_id = o.owner_id " - " WHERE " - "n.id = $1 ", - networkId - ); - int64_t hookCount = row[0].as(); - if (hookCount > 0) { - notifyNewMember(networkId, memberId); + 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;; } } - const uint64_t nwidInt = OSUtils::jsonIntHex(config["nwid"], 0ULL); - const uint64_t memberidInt = OSUtils::jsonIntHex(config["id"], 0ULL); + res = PQexec(conn, "COMMIT"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error committing ip address data: %s\n", PQresultErrorMessage(res)); + } + + PQclear(res); + + const uint64_t nwidInt = OSUtils::jsonIntHex((*config)["nwid"], 0ULL); + const uint64_t memberidInt = OSUtils::jsonIntHex((*config)["id"], 0ULL); if (nwidInt && memberidInt) { nlohmann::json nwOrig; nlohmann::json memOrig; - nlohmann::json memNew(config); + nlohmann::json memNew(*config); get(nwidInt, nwOrig, memberidInt, memOrig); _memberChanged(memOrig, memNew, qitem.second); } else { - fprintf(stderr, "%s: Can't notify of change. Error parsing nwid or memberid: %llu-%llu\n", _myAddressStr.c_str(), (unsigned long long)nwidInt, (unsigned long long)memberidInt); + fprintf(stderr, "Can't notify of change. Error parsing nwid or memberid: %llu-%llu\n", (unsigned long long)nwidInt, (unsigned long long)memberidInt); } + } catch (std::exception &e) { - fprintf(stderr, "%s ERROR: Error updating member %s-%s: %s\n", _myAddressStr.c_str(), networkId.c_str(), memberId.c_str(), e.what()); + fprintf(stderr, "ERROR: Error updating member: %s\n", e.what()); } } else if (objtype == "network") { try { - // fprintf(stderr, "%s: commitThread: network\n", _myAddressStr.c_str()); - pqxx::work w(*c->c); + std::string id = (*config)["id"]; + std::string controllerId = _myAddressStr.c_str(); + std::string name = (*config)["name"]; + std::string remoteTraceTarget("NULL"); + if (!(*config)["remoteTraceTarget"].is_null()) { + remoteTraceTarget = (*config)["remoteTraceTarget"]; + } + std::string rulesSource; + if ((*config)["rulesSource"].is_string()) { + rulesSource = (*config)["rulesSource"]; + } + std::string caps = OSUtils::jsonDump((*config)["capabilitles"], -1); + std::string now = std::to_string(OSUtils::now()); + std::string mtu = std::to_string((int)(*config)["mtu"]); + std::string mcastLimit = std::to_string((int)(*config)["multicastLimit"]); + std::string rtraceLevel = std::to_string((int)(*config)["remoteTraceLevel"]); + std::string rules = OSUtils::jsonDump((*config)["rules"], -1); + std::string tags = OSUtils::jsonDump((*config)["tags"], -1); + std::string v4mode = OSUtils::jsonDump((*config)["v4AssignMode"],-1); + std::string v6mode = OSUtils::jsonDump((*config)["v6AssignMode"], -1); + bool enableBroadcast = (*config)["enableBroadcast"]; + bool isPrivate = (*config)["private"]; - std::string id = config["id"]; - std::string remoteTraceTarget = ""; - if(!config["remoteTraceTarget"].is_null()) { - remoteTraceTarget = config["remoteTraceTarget"]; - } - std::string rulesSource = ""; - if (config["rulesSource"].is_string()) { - rulesSource = config["rulesSource"]; - } + const char *values[16] = { + id.c_str(), + controllerId.c_str(), + caps.c_str(), + enableBroadcast ? "true" : "false", + now.c_str(), + mtu.c_str(), + mcastLimit.c_str(), + name.c_str(), + isPrivate ? "true" : "false", + rtraceLevel.c_str(), + (remoteTraceTarget == "NULL" ? NULL : remoteTraceTarget.c_str()), + rules.c_str(), + rulesSource.c_str(), + tags.c_str(), + v4mode.c_str(), + v6mode.c_str(), + }; // This ugly query exists because when we want to mirror networks to/from // another data store (e.g. FileDB or LFDB) it is possible to get a network @@ -1515,15 +1075,15 @@ void PostgreSQL::commitThread() // the owner_id to the "first" global admin in the user DB if the record // did not previously exist. If the record already exists owner_id is left // unchanged, so owner_id should be left out of the update clause. - pqxx::result res = w.exec_params0( + PGresult *res = PQexecParams(conn, "INSERT INTO ztc_network (id, creation_time, owner_id, controller_id, capabilities, enable_broadcast, " "last_modified, mtu, multicast_limit, name, private, " "remote_trace_level, remote_trace_target, rules, rules_source, " - "tags, v4_assign_mode, v6_assign_mode, sso_enabled) VALUES (" + "tags, v4_assign_mode, v6_assign_mode) VALUES (" "$1, TO_TIMESTAMP($5::double precision/1000), " "(SELECT user_id AS owner_id FROM ztc_global_permissions WHERE authorize = true AND del = true AND modify = true AND read = true LIMIT 1)," "$2, $3, $4, TO_TIMESTAMP($5::double precision/1000), " - "$6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) " + "$6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) " "ON CONFLICT (id) DO UPDATE set controller_id = EXCLUDED.controller_id, " "capabilities = EXCLUDED.capabilities, enable_broadcast = EXCLUDED.enable_broadcast, " "last_modified = EXCLUDED.last_modified, mtu = EXCLUDED.mtu, " @@ -1531,42 +1091,112 @@ void PostgreSQL::commitThread() "private = EXCLUDED.private, remote_trace_level = EXCLUDED.remote_trace_level, " "remote_trace_target = EXCLUDED.remote_trace_target, rules = EXCLUDED.rules, " "rules_source = EXCLUDED.rules_source, tags = EXCLUDED.tags, " - "v4_assign_mode = EXCLUDED.v4_assign_mode, v6_assign_mode = EXCLUDED.v6_assign_mode, " - "sso_enabled = EXCLUDED.sso_enabled", - id, - _myAddressStr, - OSUtils::jsonDump(config["capabilities"], -1), - (bool)config["enableBroadcast"], - OSUtils::now(), - (int)config["mtu"], - (int)config["multicastLimit"], - OSUtils::jsonString(config["name"],""), - (bool)config["private"], - (int)config["remoteTraceLevel"], - remoteTraceTarget, - OSUtils::jsonDump(config["rules"], -1), - rulesSource, - OSUtils::jsonDump(config["tags"], -1), - OSUtils::jsonDump(config["v4AssignMode"],-1), - OSUtils::jsonDump(config["v6AssignMode"], -1), - OSUtils::jsonBool(config["ssoEnabled"], false)); + "v4_assign_mode = EXCLUDED.v4_assign_mode, v6_assign_mode = EXCLUDED.v6_assign_mode", + 16, + NULL, + values, + NULL, + NULL, + 0); - res = w.exec_params0("DELETE FROM ztc_network_assignment_pool WHERE network_id = $1", 0); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating network record: %s\n", PQresultErrorMessage(res)); + PQclear(res); + delete config; + config = nullptr; + continue; + } - auto pool = config["ipAssignmentPools"]; + PQclear(res); + + res = PQexec(conn, "BEGIN"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error beginnning transaction: %s\n", PQresultErrorMessage(res)); + PQclear(res); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + const char *params[1] = { + id.c_str() + }; + res = PQexecParams(conn, + "DELETE FROM ztc_network_assignment_pool WHERE network_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating assignment pool: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + PQclear(res); + + auto pool = (*config)["ipAssignmentPools"]; bool err = false; for (auto i = pool.begin(); i != pool.end(); ++i) { std::string start = (*i)["ipRangeStart"]; std::string end = (*i)["ipRangeEnd"]; + const char *p[3] = { + id.c_str(), + start.c_str(), + end.c_str() + }; - res = w.exec_params0( + res = PQexecParams(conn, "INSERT INTO ztc_network_assignment_pool (network_id, ip_range_start, ip_range_end) " - "VALUES ($1, $2, $3)", id, start, end); + "VALUES ($1, $2, $3)", + 3, + NULL, + p, + NULL, + NULL, + 0); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating assignment pool: %s\n", PQresultErrorMessage(res)); + PQclear(res); + err = true; + break; + } + PQclear(res); + } + if (err) { + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; } - res = w.exec_params0("DELETE FROM ztc_network_route WHERE network_id = $1", id); + res = PQexecParams(conn, + "DELETE FROM ztc_network_route WHERE network_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); - auto routes = config["routes"]; + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating routes: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + + auto routes = (*config)["routes"]; err = false; for (auto i = routes.begin(); i != routes.end(); ++i) { std::string t = (*i)["target"]; @@ -1586,371 +1216,265 @@ void PostgreSQL::commitThread() via = (*i)["via"]; } - res = w.exec_params0("INSERT INTO ztc_network_route (network_id, address, bits, via) VALUES ($1, $2, $3, $4)", - id, targetAddr, targetBits, (via == "NULL" ? NULL : via.c_str())); + const char *p[4] = { + id.c_str(), + targetAddr.c_str(), + targetBits.c_str(), + (via == "NULL" ? NULL : via.c_str()), + }; + + res = PQexecParams(conn, + "INSERT INTO ztc_network_route (network_id, address, bits, via) VALUES ($1, $2, $3, $4)", + 4, + NULL, + p, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating routes: %s\n", PQresultErrorMessage(res)); + PQclear(res); + err = true; + break; + } + PQclear(res); } if (err) { - fprintf(stderr, "%s: route add error\n", _myAddressStr.c_str()); - w.abort(); - _pool->unborrow(c); + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; continue; } - auto dns = config["dns"]; - std::string domain = dns["domain"]; - std::stringstream servers; - servers << "{"; - for (auto j = dns["servers"].begin(); j < dns["servers"].end(); ++j) { - servers << *j; - if ( (j+1) != dns["servers"].end()) { - servers << ","; - } + res = PQexec(conn, "COMMIT"); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error committing network update: %s\n", PQresultErrorMessage(res)); } - servers << "}"; + PQclear(res); - std::string s = servers.str(); - - res = w.exec_params0("INSERT INTO ztc_network_dns (network_id, domain, servers) VALUES ($1, $2, $3) ON CONFLICT (network_id) DO UPDATE SET domain = EXCLUDED.domain, servers = EXCLUDED.servers", - id, domain, s); - - w.commit(); - - const uint64_t nwidInt = OSUtils::jsonIntHex(config["nwid"], 0ULL); + const uint64_t nwidInt = OSUtils::jsonIntHex((*config)["nwid"], 0ULL); if (nwidInt) { nlohmann::json nwOrig; - nlohmann::json nwNew(config); + nlohmann::json nwNew(*config); get(nwidInt, nwOrig); _networkChanged(nwOrig, nwNew, qitem.second); } else { - fprintf(stderr, "%s: Can't notify network changed: %llu\n", _myAddressStr.c_str(), (unsigned long long)nwidInt); + fprintf(stderr, "Can't notify network changed: %llu\n", (unsigned long long)nwidInt); } + } catch (std::exception &e) { - fprintf(stderr, "%s ERROR: Error updating network: %s\n", _myAddressStr.c_str(), e.what()); - } - if (_redisMemberStatus) { - try { - std::string id = config["id"]; - std::string controllerId = _myAddressStr.c_str(); - std::string key = "networks:{" + controllerId + "}"; - if (_rc->clusterMode) { - _cluster->sadd(key, id); - } else { - _redis->sadd(key, id); - } - } catch (sw::redis::Error &e) { - fprintf(stderr, "ERROR: Error adding network to Redis: %s\n", e.what()); - } + fprintf(stderr, "ERROR: Error updating member: %s\n", e.what()); } } else if (objtype == "_delete_network") { - // fprintf(stderr, "%s: commitThread: delete network\n", _myAddressStr.c_str()); try { - pqxx::work w(*c->c); + std::string networkId = (*config)["nwid"]; + const char *values[1] = { + networkId.c_str() + }; + PGresult * res = PQexecParams(conn, + "UPDATE ztc_network SET deleted = true WHERE id = $1", + 1, + NULL, + values, + NULL, + NULL, + 0); - std::string networkId = config["nwid"]; - - pqxx::result res = w.exec_params0("UPDATE ztc_network SET deleted = true WHERE id = $1", - networkId); - - w.commit(); - } catch (std::exception &e) { - fprintf(stderr, "%s ERROR: Error deleting network: %s\n", _myAddressStr.c_str(), e.what()); - } - if (_redisMemberStatus) { - try { - std::string id = config["id"]; - std::string controllerId = _myAddressStr.c_str(); - std::string key = "networks:{" + controllerId + "}"; - if (_rc->clusterMode) { - _cluster->srem(key, id); - _cluster->del("network-nodes-online:{"+controllerId+"}:"+id); - } else { - _redis->srem(key, id); - _redis->del("network-nodes-online:{"+controllerId+"}:"+id); - } - } catch (sw::redis::Error &e) { - fprintf(stderr, "ERROR: Error adding network to Redis: %s\n", e.what()); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error deleting network: %s\n", PQresultErrorMessage(res)); } - } + PQclear(res); + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error deleting network: %s\n", e.what()); + } } else if (objtype == "_delete_member") { - // fprintf(stderr, "%s commitThread: delete member\n", _myAddressStr.c_str()); try { - pqxx::work w(*c->c); + std::string memberId = (*config)["id"]; + std::string networkId = (*config)["nwid"]; - std::string memberId = config["id"]; - std::string networkId = config["nwid"]; + const char *values[2] = { + memberId.c_str(), + networkId.c_str() + }; - pqxx::result res = w.exec_params0( + PGresult *res = PQexecParams(conn, "UPDATE ztc_member SET hidden = true, deleted = true WHERE id = $1 AND network_id = $2", - memberId, networkId); + 2, + NULL, + values, + NULL, + NULL, + 0); - w.commit(); - } catch (std::exception &e) { - fprintf(stderr, "%s ERROR: Error deleting member: %s\n", _myAddressStr.c_str(), e.what()); - } - if (_redisMemberStatus) { - try { - std::string memberId = config["id"]; - std::string networkId = config["nwid"]; - std::string controllerId = _myAddressStr.c_str(); - std::string key = "network-nodes-all:{" + controllerId + "}:" + networkId; - if (_rc->clusterMode) { - _cluster->srem(key, memberId); - _cluster->del("member:{"+controllerId+"}:"+networkId+":"+memberId); - } else { - _redis->srem(key, memberId); - _redis->del("member:{"+controllerId+"}:"+networkId+":"+memberId); - } - } catch (sw::redis::Error &e) { - fprintf(stderr, "ERROR: Error deleting member from Redis: %s\n", e.what()); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error deleting member: %s\n", PQresultErrorMessage(res)); } + + PQclear(res); + } catch (std::exception &e) { + fprintf(stderr, "ERROR: Error deleting member: %s\n", e.what()); } } else { - fprintf(stderr, "%s ERROR: unknown objtype\n", _myAddressStr.c_str()); + fprintf(stderr, "ERROR: unknown objtype"); } } catch (std::exception &e) { - fprintf(stderr, "%s ERROR: Error getting objtype: %s\n", _myAddressStr.c_str(), e.what()); + fprintf(stderr, "ERROR: Error getting objtype: %s\n", e.what()); } - _pool->unborrow(c); - c.reset(); + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } - fprintf(stderr, "%s commitThread finished\n", _myAddressStr.c_str()); -} - -void PostgreSQL::notifyNewMember(const std::string &networkID, const std::string &memberID) { - smeeclient::smee_client_notify_network_joined( - _smee, - networkID.c_str(), - memberID.c_str()); + PQfinish(conn); + if (_run == 1) { + fprintf(stderr, "ERROR: %s commitThread should still be running! Exiting Controller.\n", _myAddressStr.c_str()); + exit(7); + } } void PostgreSQL::onlineNotificationThread() { - waitForReady(); - if (_redisMemberStatus) { - onlineNotification_Redis(); - } else { - onlineNotification_Postgres(); + PGconn *conn = getPgConn(); + if (PQstatus(conn) == CONNECTION_BAD) { + fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); + PQfinish(conn); + exit(1); } -} - -/** - * ONLY UNCOMMENT FOR TEMPORARY DB MAINTENANCE - * - * This define temporarily turns off writing to the member status table - * so it can be reindexed when the indexes get too large. - */ - -// #define DISABLE_MEMBER_STATUS 1 - -void PostgreSQL::onlineNotification_Postgres() -{ _connected = 1; - nlohmann::json jtmp1, jtmp2; - while (_run == 1) { - auto c = _pool->borrow(); - auto c2 = _pool->borrow(); - try { - fprintf(stderr, "%s onlineNotification_Postgres\n", _myAddressStr.c_str()); - std::unordered_map< std::pair,std::pair,_PairHasher > lastOnline; - { - std::lock_guard l(_lastOnline_l); - lastOnline.swap(_lastOnline); - } - -#ifndef DISABLE_MEMBER_STATUS - pqxx::work w(*c->c); - pqxx::work w2(*c2->c); - - fprintf(stderr, "online notification tick\n"); - - bool firstRun = true; - bool memberAdded = false; - int updateCount = 0; - - pqxx::pipeline pipe(w); - - for (auto i=lastOnline.begin(); i != lastOnline.end(); ++i) { - updateCount += 1; - uint64_t nwid_i = i->first.first; - char nwidTmp[64]; - char memTmp[64]; - char ipTmp[64]; - OSUtils::ztsnprintf(nwidTmp,sizeof(nwidTmp), "%.16llx", nwid_i); - OSUtils::ztsnprintf(memTmp,sizeof(memTmp), "%.10llx", i->first.second); - - if(!get(nwid_i, jtmp1, i->first.second, jtmp2)) { - continue; // skip non existent networks/members - } - - std::string networkId(nwidTmp); - std::string memberId(memTmp); - - try { - pqxx::row r = w2.exec_params1("SELECT id, network_id FROM ztc_member WHERE network_id = $1 AND id = $2", - networkId, memberId); - } catch (pqxx::unexpected_rows &e) { - continue; - } - - int64_t ts = i->second.first; - std::string ipAddr = i->second.second.toIpString(ipTmp); - std::string timestamp = std::to_string(ts); - - std::stringstream memberUpdate; - memberUpdate << "INSERT INTO ztc_member_status (network_id, member_id, address, last_updated) VALUES " - << "('" << networkId << "', '" << memberId << "', "; - if (ipAddr.empty()) { - memberUpdate << "NULL, "; - } else { - memberUpdate << "'" << ipAddr << "', "; - } - memberUpdate << "TO_TIMESTAMP(" << timestamp << "::double precision/1000)) " - << " ON CONFLICT (network_id, member_id) DO UPDATE SET address = EXCLUDED.address, last_updated = EXCLUDED.last_updated"; - - pipe.insert(memberUpdate.str()); - Metrics::pgsql_node_checkin++; - } - while(!pipe.empty()) { - pipe.retrieve(); - } - - pipe.complete(); - w.commit(); - fprintf(stderr, "%s: Updated online status of %d members\n", _myAddressStr.c_str(), updateCount); -#endif - } catch (std::exception &e) { - fprintf(stderr, "%s: error in onlinenotification thread: %s\n", _myAddressStr.c_str(), e.what()); - } - _pool->unborrow(c2); - _pool->unborrow(c); - - ConnectionPoolStats stats = _pool->get_stats(); - fprintf(stderr, "%s pool stats: in use size: %llu, available size: %llu, total: %llu\n", - _myAddressStr.c_str(), stats.borrowed_size, stats.pool_size, (stats.borrowed_size + stats.pool_size)); - - std::this_thread::sleep_for(std::chrono::seconds(10)); - } - fprintf(stderr, "%s: Fell out of run loop in onlineNotificationThread\n", _myAddressStr.c_str()); - if (_run == 1) { - fprintf(stderr, "ERROR: %s onlineNotificationThread should still be running! Exiting Controller.\n", _myAddressStr.c_str()); - exit(6); - } -} - -void PostgreSQL::onlineNotification_Redis() -{ - _connected = 1; - - char buf[11] = {0}; - std::string controllerId = std::string(_myAddress.toString(buf)); + //int64_t lastUpdatedNetworkStatus = 0; + std::unordered_map< std::pair,int64_t,_PairHasher > lastOnlineCumulative; while (_run == 1) { - fprintf(stderr, "onlineNotification tick\n"); - auto start = std::chrono::high_resolution_clock::now(); - uint64_t count = 0; + if (PQstatus(conn) != CONNECTION_OK) { + fprintf(stderr, "ERROR: Online Notification thread lost connection to Postgres."); + PQfinish(conn); + exit(5); + } + + // map used to send notifications to front end + std::unordered_map> updateMap; std::unordered_map< std::pair,std::pair,_PairHasher > lastOnline; { std::lock_guard l(_lastOnline_l); lastOnline.swap(_lastOnline); } - try { - if (!lastOnline.empty()) { - if (_rc->clusterMode) { - auto tx = _cluster->transaction(controllerId, true, false); - count = _doRedisUpdate(tx, controllerId, lastOnline); - } else { - auto tx = _redis->transaction(true, false); - count = _doRedisUpdate(tx, controllerId, lastOnline); - } - } - } catch (sw::redis::Error &e) { - fprintf(stderr, "Error in online notification thread (redis): %s\n", e.what()); - } - auto end = std::chrono::high_resolution_clock::now(); - auto dur = std::chrono::duration_cast(end - start); - auto total = dur.count(); + PGresult *res = NULL; - fprintf(stderr, "onlineNotification ran in %llu ms\n", total); - - std::this_thread::sleep_for(std::chrono::seconds(5)); - } -} - -uint64_t PostgreSQL::_doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId, - std::unordered_map< std::pair,std::pair,_PairHasher > &lastOnline) - -{ - nlohmann::json jtmp1, jtmp2; - uint64_t count = 0; - for (auto i=lastOnline.begin(); i != lastOnline.end(); ++i) { - uint64_t nwid_i = i->first.first; - uint64_t memberid_i = i->first.second; - char nwidTmp[64]; - char memTmp[64]; - char ipTmp[64]; - OSUtils::ztsnprintf(nwidTmp,sizeof(nwidTmp), "%.16llx", nwid_i); - OSUtils::ztsnprintf(memTmp,sizeof(memTmp), "%.10llx", memberid_i); - - if (!get(nwid_i, jtmp1, memberid_i, jtmp2)){ - continue; // skip non existent members/networks - } - - std::string networkId(nwidTmp); - std::string memberId(memTmp); - - int64_t ts = i->second.first; - std::string ipAddr = i->second.second.toIpString(ipTmp); - std::string timestamp = std::to_string(ts); - - std::unordered_map record = { - {"id", memberId}, - {"address", ipAddr}, - {"last_updated", std::to_string(ts)} - }; - tx.zadd("nodes-online:{"+controllerId+"}", memberId, ts) - .zadd("nodes-online2:{"+controllerId+"}", networkId+"-"+memberId, ts) - .zadd("network-nodes-online:{"+controllerId+"}:"+networkId, memberId, ts) - .zadd("active-networks:{"+controllerId+"}", networkId, ts) - .sadd("network-nodes-all:{"+controllerId+"}:"+networkId, memberId) - .hmset("member:{"+controllerId+"}:"+networkId+":"+memberId, record.begin(), record.end()); - ++count; - Metrics::redis_node_checkin++; - } - - // expire records from all-nodes and network-nodes member list - uint64_t expireOld = OSUtils::now() - 300000; - - tx.zremrangebyscore("nodes-online:{"+controllerId+"}", - sw::redis::RightBoundedInterval(expireOld, - sw::redis::BoundType::LEFT_OPEN)); - tx.zremrangebyscore("nodes-online2:{"+controllerId+"}", - sw::redis::RightBoundedInterval(expireOld, - sw::redis::BoundType::LEFT_OPEN)); - tx.zremrangebyscore("active-networks:{"+controllerId+"}", - sw::redis::RightBoundedInterval(expireOld, - sw::redis::BoundType::LEFT_OPEN)); - { - std::shared_lock l(_networks_l); - for (const auto &it : _networks) { - uint64_t nwid_i = it.first; + std::stringstream memberUpdate; + memberUpdate << "INSERT INTO ztc_member_status (network_id, member_id, address, last_updated) VALUES "; + bool firstRun = true; + bool memberAdded = false; + for (auto i=lastOnline.begin(); i != lastOnline.end(); ++i) { + uint64_t nwid_i = i->first.first; char nwidTmp[64]; + char memTmp[64]; + char ipTmp[64]; OSUtils::ztsnprintf(nwidTmp,sizeof(nwidTmp), "%.16llx", nwid_i); - tx.zremrangebyscore("network-nodes-online:{"+controllerId+"}:"+nwidTmp, - sw::redis::RightBoundedInterval(expireOld, sw::redis::BoundType::LEFT_OPEN)); - } - } - tx.exec(); - fprintf(stderr, "%s: Updated online status of %d members\n", _myAddressStr.c_str(), count); + OSUtils::ztsnprintf(memTmp,sizeof(memTmp), "%.10llx", i->first.second); - return count; + auto found = _networks.find(nwid_i); + 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() + }; + + res = PQexecParams(conn, + "SELECT id, network_id FROM ztc_member WHERE network_id = $1 AND id = $2", + 2, + NULL, + qvals, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr, "Member count failed: %s", PQerrorMessage(conn)); + PQclear(res); + continue; + } + + int nrows = PQntuples(res); + PQclear(res); + + if (nrows == 1) { + 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 { + memberUpdate << ", "; + } + + memberUpdate << "('" << networkId << "', '" << memberId << "', "; + if (ipAddr.empty()) { + memberUpdate << "NULL, "; + } else { + memberUpdate << "'" << ipAddr << "', "; + } + memberUpdate << "TO_TIMESTAMP(" << timestamp << "::double precision/1000))"; + memberAdded = true; + } else if (nrows > 1) { + fprintf(stderr, "nrows > 1?!?"); + continue; + } else { + continue; + } + } + memberUpdate << " ON CONFLICT (network_id, member_id) DO UPDATE SET address = EXCLUDED.address, last_updated = EXCLUDED.last_updated;"; + + if (memberAdded) { + res = PQexec(conn, memberUpdate.str().c_str()); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "Multiple insert failed: %s", PQerrorMessage(conn)); + } + PQclear(res); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + fprintf(stderr, "%s: Fell out of run loop in onlineNotificationThread\n", _myAddressStr.c_str()); + PQfinish(conn); + if (_run == 1) { + fprintf(stderr, "ERROR: %s onlineNotificationThread should still be running! Exiting Controller.\n", _myAddressStr.c_str()); + exit(6); + } } +PGconn *PostgreSQL::getPgConn(OverrideMode m) +{ + if (m == ALLOW_PGBOUNCER_OVERRIDE) { + char *connStr = getenv("PGBOUNCER_CONNSTR"); + if (connStr != NULL) { + fprintf(stderr, "PGBouncer Override\n"); + std::string conn(connStr); + conn += " application_name=controller-"; + conn += _myAddressStr.c_str(); + return PQconnectdb(conn.c_str()); + } + } + + return PQconnectdb(_connString.c_str()); +} #endif //ZT_CONTROLLER_USE_LIBPQ diff --git a/controller/PostgreSQL.hpp b/controller/PostgreSQL.hpp index b583bd69..035f5b5a 100644 --- a/controller/PostgreSQL.hpp +++ b/controller/PostgreSQL.hpp @@ -4,7 +4,7 @@ * 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: 2026-01-01 + * 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. @@ -20,92 +20,24 @@ #define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4 -#include "ConnectionPool.hpp" -#include - -#include -#include - -#include "../node/Metrics.hpp" - extern "C" { typedef struct pg_conn PGconn; } -namespace smeeclient { - struct SmeeClient; -} - namespace ZeroTier { -struct RedisConfig; - - -class PostgresConnection : public Connection { -public: - virtual ~PostgresConnection() { - } - - std::shared_ptr c; - int a; -}; - - -class PostgresConnFactory : public ConnectionFactory { -public: - PostgresConnFactory(std::string &connString) - : m_connString(connString) - { - } - - virtual std::shared_ptr create() { - Metrics::conn_counter++; - auto c = std::shared_ptr(new PostgresConnection()); - c->c = std::make_shared(m_connString); - return std::static_pointer_cast(c); - } -private: - std::string m_connString; -}; - -class PostgreSQL; - -class MemberNotificationReceiver : public pqxx::notification_receiver { -public: - MemberNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel); - virtual ~MemberNotificationReceiver() { - fprintf(stderr, "MemberNotificationReceiver destroyed\n"); - } - - virtual void operator() (const std::string &payload, int backendPid); -private: - PostgreSQL *_psql; -}; - -class NetworkNotificationReceiver : public pqxx::notification_receiver { -public: - NetworkNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel); - virtual ~NetworkNotificationReceiver() { - fprintf(stderr, "NetworkNotificationReceiver destroyed\n"); - }; - - virtual void operator() (const std::string &payload, int packend_pid); -private: - PostgreSQL *_psql; -}; +struct MQConfig; /** * A controller database driver that talks to PostgreSQL * * This is for use with ZeroTier Central. Others are free to build and use it - * but be aware that we might change it at any time. + * but be aware taht we might change it at any time. */ class PostgreSQL : public DB { - friend class MemberNotificationReceiver; - friend class NetworkNotificationReceiver; public: - PostgreSQL(const Identity &myId, const char *path, int listenPort, RedisConfig *rc); + PostgreSQL(const Identity &myId, const char *path, int listenPort, MQConfig *mqc = NULL); virtual ~PostgreSQL(); virtual bool waitForReady(); @@ -114,49 +46,33 @@ public: virtual void eraseNetwork(const uint64_t networkId); virtual void eraseMember(const uint64_t networkId, const uint64_t memberId); virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress); - virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL); protected: struct _PairHasher { inline std::size_t operator()(const std::pair &p) const { return (std::size_t)(p.first ^ p.second); } }; - virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) { - DB::_memberChanged(old, memberConfig, notifyListeners); - } - - virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) { - DB::_networkChanged(old, networkConfig, notifyListeners); - } private: - void initializeNetworks(); - void initializeMembers(); + void initializeNetworks(PGconn *conn); + void initializeMembers(PGconn *conn); void heartbeat(); void membersDbWatcher(); - void _membersWatcher_Postgres(); + void _membersWatcher_Postgres(PGconn *conn); + void _membersWatcher_RabbitMQ(); void networksDbWatcher(); - void _networksWatcher_Postgres(); - - void _membersWatcher_Redis(); - void _networksWatcher_Redis(); + void _networksWatcher_Postgres(PGconn *conn); + void _networksWatcher_RabbitMQ(); void commitThread(); void onlineNotificationThread(); - void onlineNotification_Postgres(); - void onlineNotification_Redis(); - uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId, - std::unordered_map< std::pair,std::pair,_PairHasher > &lastOnline); - - void configureSmee(); - void notifyNewMember(const std::string &networkID, const std::string &memberID); enum OverrideMode { ALLOW_PGBOUNCER_OVERRIDE = 0, NO_OVERRIDE = 1 }; - std::shared_ptr > _pool; + PGconn * getPgConn( OverrideMode m = ALLOW_PGBOUNCER_OVERRIDE ); const Identity _myId; const Address _myAddress; @@ -179,14 +95,8 @@ private: mutable volatile bool _waitNoticePrinted; int _listenPort; - uint8_t _ssoPsk[48]; - RedisConfig *_rc; - std::shared_ptr _redis; - std::shared_ptr _cluster; - bool _redisMemberStatus; - - smeeclient::SmeeClient *_smee; + MQConfig *_mqc; }; } // namespace ZeroTier diff --git a/controller/README.md b/controller/README.md index 41cfd3ff..368613a6 100644 --- a/controller/README.md +++ b/controller/README.md @@ -3,7 +3,7 @@ Network Controller Microservice Every ZeroTier virtual network has a *network controller* responsible for admitting members to the network, issuing certificates, and issuing default configuration information. -This is our reference controller implementation and is almost the same as the one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). The only difference is the database backend used. +This is our reference controller implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets. Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files. @@ -19,6 +19,10 @@ Since ZeroTier nodes are mobile and do not need static IPs, implementing high av ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it. +### PostgreSQL Database Implementation + +The default controller stores its data in the filesystem in `controller.d` under ZeroTier's home folder. There's an alternative implementation that stores data in PostgreSQL that can be built with `make central-controller`. Right now this is only guaranteed to build and run on Centos 7 Linux with PostgreSQL 10 installed via the [PostgreSQL Yum Repository](https://www.postgresql.org/download/linux/redhat/) and is designed for use with [ZeroTier Central](https://my.zerotier.com/). You're welcome to use it but we don't "officially" support it for end-user use and it could change at any time. + ### Upgrading from Older (1.1.14 or earlier) Versions Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code. @@ -39,17 +43,190 @@ While networks with any valid ID can be added to the controller's database, it w The controller JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrect types may be ignored, set to default values, or set to undefined values. -Full documentation of the Controller API can be found on our [documentation site](https://docs.zerotier.com/service/v1#tag/controller) +#### `/controller` -### Prometheus Metrics + * Purpose: Check for controller function and return controller status + * Methods: GET + * Returns: { object } -Controller specific metrics are available from the `/metrics` endpoint. +| Field | Type | Description | Writable | +| ------------------ | ----------- | ------------------------------------------------- | -------- | +| controller | boolean | Always 'true' | no | +| apiVersion | integer | Controller API version, currently 3 | no | +| clock | integer | Current clock on controller, ms since epoch | no | + +#### `/controller/network` + + * Purpose: List all networks hosted by this controller + * Methods: GET + * Returns: [ string, ... ] + +This returns an array of 16-digit hexadecimal network IDs. + +#### `/controller/network/` + + * Purpose: Create, configure, and delete hosted networks + * Methods: GET, POST, DELETE + * Returns: { object } + +By making queries to this path you can create, configure, and delete networks. DELETE is final, so don't do it unless you really mean it. + +When POSTing new networks take care that their IDs are not in use, otherwise you may overwrite an existing one. To create a new network with a random unused ID, POST to `/controller/network/##########______`. The #'s are the controller's 10-digit ZeroTier address and they're followed by six underscores. Check the `nwid` field of the returned JSON object for your network's newly allocated ID. Subsequent POSTs to this network must refer to its actual path. + +Example: + +`curl -X POST --header "X-ZT1-Auth: secret" -d '{"name":"my network"}' http://localhost:9993/controller/network/305f406058______` + +**Network object format:** + +| Field | Type | Description | Writable | +| --------------------- | ------------- | ------------------------------------------------- | -------- | +| id | string | 16-digit network ID | no | +| nwid | string | 16-digit network ID (legacy) | no | +| objtype | string | Always "network" | no | +| name | string | A short name for this network | YES | +| creationTime | integer | Time network record was created (ms since epoch) | no | +| private | boolean | Is access control enabled? | YES | +| enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES | +| v4AssignMode | object | IPv4 management and assign options (see below) | YES | +| 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 | +| 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 | +| rules | array[object] | Traffic rules; see below | YES | +| capabilities | array[object] | Array of capability objects (see below) | YES | +| tags | array[object] | Array of tag objects (see below) | YES | +| remoteTraceTarget | string | 10-digit ZeroTier ID of remote trace target | YES | +| remoteTraceLevel | integer | Remote trace verbosity level | YES | + + * Networks without rules won't carry any traffic. If you don't specify any on network creation an "accept anything" rule set will automatically be added. + * Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members. + * The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are otherwise not common. + * Changing the MTU can be disruptive and on some operating systems may require a leave/rejoin of the network or a restart of the ZeroTier service. + +**Auto-Assign Modes:** + +Auto assign modes (`v4AssignMode` and `v6AssignMode`) contain objects that map assignment modes to booleans. + +For IPv4 the only valid setting is `zt` which, if true, causes IPv4 addresses to be auto-assigned from `ipAssignmentPools` to members that do not have an IPv4 assignment. Note that active bridges are exempt and will not get auto-assigned IPs since this can interfere with bridging. (You can still manually assign one if you want.) + +IPv6 includes this option and two others: `6plane` and `rfc4193`. These assign private IPv6 addresses to each member based on a deterministic assignment scheme that allows members to emulate IPv6 NDP to skip multicast for better performance and scalability. The `rfc4193` mode gives every member a /128 on a /88 network, while `6plane` gives every member a /80 within a /40 network but uses NDP emulation to route *all* IPs under that /80 to its owner. The `6plane` mode is great for use cases like Docker since it allows every member to assign IPv6 addresses within its /80 that just work instantly and globally across the network. + +**IP assignment pool object format:** + +| Field | Type | Description | +| --------------------- | ------------- | ------------------------------------------------- | +| ipRangeStart | string | Starting IP address in range | +| ipRangeEnd | string | Ending IP address in range (inclusive) | + +Pools are only used if auto-assignment is on for the given address type (IPv4 or IPv6) and if the entire range falls within a managed route. + +IPv6 ranges work just like IPv4 ranges and look like this: + + { + "ipRangeStart": "fd00:feed:feed:beef:0000:0000:0000:0000", + "ipRangeEnd": "fd00:feed:feed:beef:ffff:ffff:ffff:ffff" + } + +(You can POST a shortened-form IPv6 address but the API will always report back un-shortened canonical form addresses.) + +That defines a range within network `fd00:feed:feed:beef::/64` that contains up to 2^64 addresses. If an IPv6 range is large enough, the controller will assign addresses by placing each member's device ID into the address in a manner similar to the RFC4193 and 6PLANE modes. Otherwise it will assign addresses at random. + +**Rule object format:** + +Each rule is actually a sequence of zero or more `MATCH_` entries in the rule array followed by an `ACTION_` entry that describes what to do if all the preceding entries match. An `ACTION_` without any preceding `MATCH_` entries is always taken, so setting a single `ACTION_ACCEPT` rule yields a network that allows all traffic. If no rules are present the default action is `ACTION_DROP`. + +Rules are evaluated in the order in which they appear in the array. There is currently a limit of 256 entries per network. Capabilities should be used if a larger and more complex rule set is needed since they allow rules to be grouped by purpose and only shipped to members that need them. + +Each rule table entry has two common fields. + +| Field | Type | Description | +| --------------------- | ------------- | ------------------------------------------------- | +| type | string | Entry type (all caps, case sensitive) | +| not | boolean | If true, MATCHes match if they don't match | + +The following fields may or may not be present depending on rule type: + +| Field | Type | Description | +| --------------------- | ------------- | ------------------------------------------------- | +| zt | string | 10-digit hex ZeroTier address | +| etherType | integer | Ethernet frame type | +| mac | string | Hex MAC address (with or without :'s) | +| ip | string | IPv4 or IPv6 address | +| ipTos | integer | IP type of service | +| ipProtocol | integer | IP protocol (e.g. TCP) | +| start | integer | Start of an integer range (e.g. port range) | +| end | integer | End of an integer range (inclusive) | +| id | integer | Tag ID | +| value | integer | Tag value or comparison value | +| mask | integer | Bit mask (for characteristics flags) | + +The entry types and their additional fields are: + +| Entry type | Description | Fields | +| ------------------------------- | ----------------------------------------------------------------- | -------------- | +| `ACTION_DROP` | Drop any packets matching this rule | (none) | +| `ACTION_ACCEPT` | Accept any packets matching this rule | (none) | +| `ACTION_TEE` | Send a copy of this packet to a node (rule parsing continues) | `zt` | +| `ACTION_REDIRECT` | Redirect this packet to another node | `zt` | +| `ACTION_DEBUG_LOG` | Output debug info on match (if built with rules engine debug) | (none) | +| `MATCH_SOURCE_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of packet sender. | `zt` | +| `MATCH_DEST_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of recipient | `zt` | +| `MATCH_ETHERTYPE` | Match Ethernet frame type | `etherType` | +| `MATCH_MAC_SOURCE` | Match source Ethernet MAC address | `mac` | +| `MATCH_MAC_DEST` | Match destination Ethernet MAC address | `mac` | +| `MATCH_IPV4_SOURCE` | Match source IPv4 address | `ip` | +| `MATCH_IPV4_DEST` | Match destination IPv4 address | `ip` | +| `MATCH_IPV6_SOURCE` | Match source IPv6 address | `ip` | +| `MATCH_IPV6_DEST` | Match destination IPv6 address | `ip` | +| `MATCH_IP_TOS` | Match IP TOS field | `ipTos` | +| `MATCH_IP_PROTOCOL` | Match IP protocol field | `ipProtocol` | +| `MATCH_IP_SOURCE_PORT_RANGE` | Match a source IP port range | `start`,`end` | +| `MATCH_IP_DEST_PORT_RANGE` | Match a destination IP port range | `start`,`end` | +| `MATCH_CHARACTERISTICS` | Match on characteristics flags | `mask`,`value` | +| `MATCH_FRAME_SIZE_RANGE` | Match a range of Ethernet frame sizes | `start`,`end` | +| `MATCH_TAGS_SAMENESS` | Match if both sides' tags differ by no more than value | `id`,`value` | +| `MATCH_TAGS_BITWISE_AND` | Match if both sides' tags AND to value | `id`,`value` | +| `MATCH_TAGS_BITWISE_OR` | Match if both sides' tags OR to value | `id`,`value` | +| `MATCH_TAGS_BITWISE_XOR` | Match if both sides' tags XOR to value | `id`,`value` | + +Important notes about rules engine behavior: + + * IPv4 and IPv6 IP address rules do not match for frames that are not IPv4 or IPv6 respectively. + * `ACTION_DEBUG_LOG` is a no-op on nodes not built with `ZT_RULES_ENGINE_DEBUGGING` enabled (see Network.cpp). If that is enabled nodes will dump a trace of rule evaluation results to *stdout* when this action is encountered but will otherwise keep evaluating rules. This is used for basic "smoke testing" of the rules engine. + * Multicast packets and packets destined for bridged devices treated a little differently. They are matched more than once. They are matched at the point of send with a NULL ZeroTier destination address, meaning that `MATCH_DEST_ZEROTIER_ADDRESS` is useless. That's because the true VL1 destination is not yet known. Then they are matched again for each true VL1 destination. On these later subsequent matches TEE actions are ignored and REDIRECT rules are interpreted as DROPs. This prevents multiple TEE or REDIRECT packets from being sent to third party devices. + * Rules in capabilities are always matched as if the current device is the sender (inbound == false). A capability specifies sender side rules that can be enforced on both sides. + +#### `/controller/network//member` + + * Purpose: Get a set of all members on this network + * Methods: GET + * Returns: { object } + +This returns a JSON object containing all member IDs as keys and their `memberRevisionCounter` values as values. + +#### `/controller/network//member/
` + + * Purpose: Create, authorize, or remove a network member + * Methods: GET, POST, DELETE + * Returns: { object } + +| Field | Type | Description | Writable | +| --------------------- | ------------- | ------------------------------------------------- | -------- | +| id | string | Member's 10-digit ZeroTier address | no | +| address | string | Member's 10-digit ZeroTier address | no | +| nwid | string | 16-digit network ID | no | +| authorized | boolean | Is member authorized? (for private networks) | YES | +| activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES | +| identity | string | Member's public ZeroTier identity (if known) | no | +| ipAssignments | array[string] | Managed IP address assignments | YES | +| revision | integer | Member revision counter | no | +| vMajor | integer | Most recently known major version | no | +| vMinor | integer | Most recently known minor version | no | +| vRev | integer | Most recently known revision | no | +| vProto | integer | Most recently known protocl version | no | + +Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored. -| Metric Name | Type | Description | -| --- | --- | --- | -| controller_network_count | Gauge | number of networks the controller is serving | -| controller_member_count | Gauge | number of network members the controller is serving | -| controller_network_change_count | Counter | number of times a network configuration is changed | -| controller_member_change_count | Counter | number of times a network member configuration is changed | -| controller_member_auth_count | Counter | number of network member auths | -| controller_member_deauth_count | Counter | number of network member deauths| diff --git a/controller/RabbitMQ.cpp b/controller/RabbitMQ.cpp new file mode 100644 index 00000000..41ebcc87 --- /dev/null +++ b/controller/RabbitMQ.cpp @@ -0,0 +1,120 @@ +/* + * 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. + */ +/****/ + +#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 new file mode 100644 index 00000000..c60af8ec --- /dev/null +++ b/controller/RabbitMQ.hpp @@ -0,0 +1,68 @@ +/* + * 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. + */ +/****/ + +#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/controller/Redis.hpp b/controller/Redis.hpp deleted file mode 100644 index 095419b0..00000000 --- a/controller/Redis.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ZT_CONTROLLER_REDIS_HPP -#define ZT_CONTROLLER_REDIS_HPP - -#include - -namespace ZeroTier { -struct RedisConfig { - std::string hostname; - int port; - std::string password; - bool clusterMode; -}; -} - -#endif \ No newline at end of file diff --git a/debian/changelog b/debian/changelog index 660562f9..dc836339 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,199 +1,3 @@ -zerotier-one (1.14.1) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Wed, 11 Sep 2024 01:00:00 -0700 - -zerotier-one (1.14.0) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Tue, 19 Mar 2024 01:00:00 -0700 - -zerotier-one (1.12.2) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Tue, 12 Sep 2023 01:00:00 -0700 - -zerotier-one (1.12.1) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Fri, 25 Aug 2023 01:00:00 -0700 - -zerotier-one (1.12.0) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Thu, 17 Aug 2023 01:00:00 -0700 - -zerotier-one (1.10.6) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Tue, 21 Mar 2023 01:00:00 -0700 - -zerotier-one (1.10.5) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Fri, 10 Mar 2023 01:00:00 -0700 - -zerotier-one (1.10.4) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 06 Mar 2023 01:00:00 -0700 - -zerotier-one (1.10.3) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Sat, 21 Jan 2023 01:00:00 -0700 - -zerotier-one (1.10.2) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Thu, 13 Oct 2022 01:00:00 -0700 - -zerotier-one (1.10.1) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 27 Jun 2022 01:00:00 -0700 - -zerotier-one (1.10.0) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Fri, 03 Jun 2022 01:00:00 -0700 - -zerotier-one (1.8.10) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Tue, 10 May 2022 01:00:00 -0700 - -zerotier-one (1.8.9) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 25 Apr 2022 01:00:00 -0700 - -zerotier-one (1.8.8) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 11 Apr 2022 01:00:00 -0700 - -zerotier-one (1.8.7) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 21 Mar 2022 01:00:00 -0700 - -zerotier-one (1.8.6) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 07 Mar 2022 01:00:00 -0700 - -zerotier-one (1.8.5) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Fri, 17 Dec 2021 01:00:00 -0700 - -zerotier-one (1.8.4) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 23 Nov 2021 01:00:00 -0700 - -zerotier-one (1.8.3) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 15 Nov 2021 01:00:00 -0700 - -zerotier-one (1.8.2) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 08 Nov 2021 01:00:00 -0700 - -zerotier-one (1.8.1) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Wed, 20 Oct 2021 01:00:00 -0700 - -zerotier-one (1.8.0) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Wed, 15 Sep 2021 01:00:00 -0700 - -zerotier-one (1.6.6) unstable; urgency=medium - - * Backport endpoint mitigation against address collision attack. - - -- Adam Ierymenko Tue, 21 Sep 2021 01:00:00 -0700 - -zerotier-one (1.6.5) unstable; urgency=medium - - * Fix path filtering bug that could cause "software laser" effect. - * Fix printf overflow in CLI (not exploitable or security related) - * Fix Windows device enumeration issue. - - -- Adam Ierymenko Tue, 13 Apr 2021 01:00:00 -0700 - -zerotier-one (1.6.4) unstable; urgency=medium - - * REALLY fix a problem causing nodes to go into a "coma" with some network configurations. - - -- Adam Ierymenko Tue, 15 Feb 2021 01:00:00 -0700 - -zerotier-one (1.6.3-1) unstable; urgency=medium - - * Fix a problem causing nodes to go into a "coma" with some network configurations. - - -- Adam Ierymenko Tue, 02 Feb 2021 01:00:00 -0700 - -zerotier-one (1.6.2-2) unstable; urgency=medium - - * This is a minor update to the 1.6.2 package to address issues with - running on ARMv6 CPUs like the Raspberry Pi Zero and original v1 Pi. - - -- Adam Ierymenko Tue, 31 Nov 2020 01:00:00 -0700 - -zerotier-one (1.6.2) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 30 Nov 2020 01:00:00 -0700 - -zerotier-one (1.6.1) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Tue, 24 Nov 2020 01:00:00 -0700 - -zerotier-one (1.6.0) unstable; urgency=medium - - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Thu, 19 Nov 2020 01:00:00 -0700 - -zerotier-one (1.5.0) unstable; urgency=medium - - * Version 1.5.0 is actually 1.6.0-beta1 - * See RELEASE-NOTES.md for release notes. - - -- Adam Ierymenko Mon, 05 Aug 2020 01:00:00 -0700 - zerotier-one (1.4.6) unstable; urgency=medium * Update default root server list diff --git a/debian/compat b/debian/compat index 9a037142..301160a9 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -10 \ No newline at end of file +8 \ No newline at end of file diff --git a/debian/control b/debian/control index b0c178ab..1eb147e0 100644 --- a/debian/control +++ b/debian/control @@ -3,14 +3,14 @@ Maintainer: Adam Ierymenko Section: net Priority: optional Standards-Version: 3.9.6 -Build-Depends: debhelper +Build-Depends: debhelper (>= 9) Vcs-Git: git://github.com/zerotier/ZeroTierOne Vcs-Browser: https://github.com/zerotier/ZeroTierOne Homepage: https://www.zerotier.com/ Package: zerotier-one Architecture: any -Depends: adduser, libstdc++6 (>= 5), openssl +Depends: ${shlibs:Depends}, ${misc:Depends}, iproute2, adduser, libstdc++6 Homepage: https://www.zerotier.com/ Description: ZeroTier network virtualization service ZeroTier One lets you join ZeroTier virtual networks and diff --git a/debian/control.wheezy b/debian/control.wheezy index fbbc40d9..a8e24084 100644 --- a/debian/control.wheezy +++ b/debian/control.wheezy @@ -10,7 +10,7 @@ Homepage: https://www.zerotier.com/ Package: zerotier-one Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libstdc++6 +Depends: ${shlibs:Depends}, ${misc:Depends}, iproute, libstdc++6 Homepage: https://www.zerotier.com/ Description: ZeroTier network virtualization service ZeroTier One lets you join ZeroTier virtual networks and diff --git a/debian/copyright b/debian/copyright index da3678d5..493e6a27 100644 --- a/debian/copyright +++ b/debian/copyright @@ -12,7 +12,7 @@ License: ZeroTier BSL 1.1 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: 2026-01-01 + 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/debian/postinst b/debian/postinst index b6e7471c..2e673aef 100644 --- a/debian/postinst +++ b/debian/postinst @@ -3,7 +3,7 @@ case "$1" in configure) if ! id zerotier-one >>/dev/null 2>&1; then - useradd --system --user-group --home-dir /var/lib/zerotier-one --shell /usr/sbin/nologin --no-create-home zerotier-one + useradd --system --user-group --home-dir /var/lib/zerotier-one --no-create-home zerotier-one fi ;; esac diff --git a/debian/rules b/debian/rules old mode 100644 new mode 100755 index 81fde680..e6644d8e --- a/debian/rules +++ b/debian/rules @@ -7,7 +7,7 @@ CXXFLAGS=-O3 -fstack-protector-strong dh $@ --with systemd override_dh_auto_build: - make + make -j 4 override_dh_systemd_start: dh_systemd_start --restart-after-upgrade diff --git a/debian/rules.wheezy b/debian/rules.wheezy old mode 100644 new mode 100755 diff --git a/debian/zerotier-one.service b/debian/zerotier-one.service index 9d6a21b0..133d4490 100644 --- a/debian/zerotier-one.service +++ b/debian/zerotier-one.service @@ -1,6 +1,6 @@ [Unit] Description=ZeroTier One -After=network-online.target network.target +After=network-online.target Wants=network-online.target [Service] diff --git a/doc/README.md b/doc/README.md index 681954cc..707c64a9 100644 --- a/doc/README.md +++ b/doc/README.md @@ -3,4 +3,4 @@ Manual Pages and Other Documentation Use "./build.sh" to build the manual pages. -You'll need either Node.js/npm installed (script will then automatically install the npm *marked-man* package) or */usr/bin/ronn*. The latter is a Ruby program packaged on some distributions as *rubygem-ronn* or *ruby-ronn* or installable as *gem install ronn*. The Node *marked-man* package and *ronn* from RubyGems are two roughly equivalent alternatives for compiling Markdown into roff/man format. +You'll need either NodeJS/npm installed (script will then automatically install the npm *marked-man* package) or */usr/bin/ronn*. The latter is a Ruby program packaged on some distributions as *rubygem-ronn* or *ruby-ronn* or installable as *gem install ronn*. The Node *marked-man* package and *ronn* from rubygems are two roughly equivalent alternatives for compiling MarkDown into roff/man format. diff --git a/doc/zerotier-one.8.md b/doc/zerotier-one.8.md index 4f465507..bd31d5c8 100644 --- a/doc/zerotier-one.8.md +++ b/doc/zerotier-one.8.md @@ -81,7 +81,7 @@ These are found in the service's working directory. If the ZeroTier One service is built with the network controller enabled, it periodically backs up its controller.db database in this file (currently every 5 minutes if there have been changes). Since this file is not a currently in use SQLite3 database it's safer to back up without corruption. On new backups the file is rotated out rather than being rewritten in place. * `iddb.d/` (directory): - Caches the public identity of every peer ZeroTier has spoken with in the last 60 days. This directory and its contents can be deleted, but this may result in slower connection initiations since it will require that we go out and re-fetch full identities for peers we're speaking to. + Caches the public identity of every peer ZeroTier has spoken with in the last 60 days. This directory and its contents can be deleted, but this may result in slower connection initations since it will require that we go out and re-fetch full identities for peers we're speaking to. * `networks.d` (directory): This caches network configurations and certificate information for networks you belong to. ZeroTier scans this directory for .conf files on startup to recall its networks, so "touch"ing an empty .conf file in this directory is a way of pre-configuring ZeroTier to join a specific network on startup without using the API. If the config file is empty ZeroTIer will just fetch it from the network's controller. diff --git a/entrypoint.sh.release b/entrypoint.sh.release deleted file mode 100644 index 284a3d41..00000000 --- a/entrypoint.sh.release +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/sh - -grepzt() { - [ -f /var/lib/zerotier-one/zerotier-one.pid -a -n "$(cat /var/lib/zerotier-one/zerotier-one.pid 2>/dev/null)" -a -d "/proc/$(cat /var/lib/zerotier-one/zerotier-one.pid 2>/dev/null)" ] - return $? -} - -mkztfile() { - file=$1 - mode=$2 - content=$3 - - mkdir -p /var/lib/zerotier-one - echo "$content" > "/var/lib/zerotier-one/$file" - chmod "$mode" "/var/lib/zerotier-one/$file" -} - -if [ "x$ZEROTIER_API_SECRET" != "x" ] -then - mkztfile authtoken.secret 0600 "$ZEROTIER_API_SECRET" -fi - -if [ "x$ZEROTIER_IDENTITY_PUBLIC" != "x" ] -then - mkztfile identity.public 0644 "$ZEROTIER_IDENTITY_PUBLIC" -fi - -if [ "x$ZEROTIER_IDENTITY_SECRET" != "x" ] -then - mkztfile identity.secret 0600 "$ZEROTIER_IDENTITY_SECRET" -fi - -mkztfile zerotier-one.port 0600 "9993" - -killzerotier() { - log "Killing zerotier" - kill $(cat /var/lib/zerotier-one/zerotier-one.pid 2>/dev/null) - exit 0 -} - -log_header() { - echo -n "\r=>" -} - -log_detail_header() { - echo -n "\r===>" -} - -log() { - echo "$(log_header)" "$@" -} - -log_params() { - title=$1 - shift - log "$title" "[$@]" -} - -log_detail() { - echo "$(log_detail_header)" "$@" -} - -log_detail_params() { - title=$1 - shift - log_detail "$title" "[$@]" -} - -trap killzerotier INT TERM - -log "Configuring networks to join" -mkdir -p /var/lib/zerotier-one/networks.d - -log_params "Joining networks from command line:" $@ -for i in "$@" -do - log_detail_params "Configuring join:" "$i" - touch "/var/lib/zerotier-one/networks.d/${i}.conf" -done - -if [ "x$ZEROTIER_JOIN_NETWORKS" != "x" ] -then - log_params "Joining networks from environment:" $ZEROTIER_JOIN_NETWORKS - for i in $ZEROTIER_JOIN_NETWORKS - do - log_detail_params "Configuring join:" "$i" - touch "/var/lib/zerotier-one/networks.d/${i}.conf" - done -fi - -log "Starting ZeroTier" -nohup /usr/sbin/zerotier-one & - -while ! grepzt -do - log_detail "ZeroTier hasn't started, waiting a second" - - if [ -f nohup.out ] - then - tail -n 10 nohup.out - fi - - sleep 1 -done - -log_params "Writing healthcheck for networks:" $@ - -cat >/healthcheck.sh < -#include -#define zt_arm_has_neon() ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0) -#elif defined(__ARM_NEON__) || defined(__ARM_NEON) -#define zt_arm_has_neon() (true) -#else -#define zt_arm_has_neon() (false) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// ciphertext buffer, message/NULL, length, nonce (8 bytes), key (32 bytes) -extern int zt_salsa2012_armneon3_xor(unsigned char *c,const unsigned char *m,unsigned long long len,const unsigned char *n,const unsigned char *k); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/arm32-neon-salsa2012-asm/salsa2012.s b/ext/arm32-neon-salsa2012-asm/salsa2012.s deleted file mode 100644 index 9e5989cd..00000000 --- a/ext/arm32-neon-salsa2012-asm/salsa2012.s +++ /dev/null @@ -1,2231 +0,0 @@ - -# qhasm: int32 input_0 - -# qhasm: int32 input_1 - -# qhasm: int32 input_2 - -# qhasm: int32 input_3 - -# qhasm: stack32 input_4 - -# qhasm: stack32 input_5 - -# qhasm: stack32 input_6 - -# qhasm: stack32 input_7 - -# qhasm: int32 caller_r4 - -# qhasm: int32 caller_r5 - -# qhasm: int32 caller_r6 - -# qhasm: int32 caller_r7 - -# qhasm: int32 caller_r8 - -# qhasm: int32 caller_r9 - -# qhasm: int32 caller_r10 - -# qhasm: int32 caller_r11 - -# qhasm: int32 caller_r14 - -# qhasm: reg128 caller_q4 - -# qhasm: reg128 caller_q5 - -# qhasm: reg128 caller_q6 - -# qhasm: reg128 caller_q7 - -# qhasm: startcode -.fpu neon -.text - -# qhasm: constant sigma: -.align 2 -sigma: - -# qhasm: const32 1634760805 -.word 1634760805 - -# qhasm: const32 857760878 -.word 857760878 - -# qhasm: const32 2036477234 -.word 2036477234 - -# qhasm: const32 1797285236 -.word 1797285236 - -# qhasm: int128 abab - -# qhasm: int128 diag0 - -# qhasm: int128 diag1 - -# qhasm: int128 diag2 - -# qhasm: int128 diag3 - -# qhasm: int128 a0 - -# qhasm: int128 a1 - -# qhasm: int128 a2 - -# qhasm: int128 a3 - -# qhasm: int128 b0 - -# qhasm: int128 b1 - -# qhasm: int128 b2 - -# qhasm: int128 b3 - -# qhasm: int128 next_diag0 - -# qhasm: int128 next_diag1 - -# qhasm: int128 next_diag2 - -# qhasm: int128 next_diag3 - -# qhasm: int128 next_a0 - -# qhasm: int128 next_a1 - -# qhasm: int128 next_a2 - -# qhasm: int128 next_a3 - -# qhasm: int128 next_b0 - -# qhasm: int128 next_b1 - -# qhasm: int128 next_b2 - -# qhasm: int128 next_b3 - -# qhasm: int128 x0x5x10x15 - -# qhasm: int128 x12x1x6x11 - -# qhasm: int128 x8x13x2x7 - -# qhasm: int128 x4x9x14x3 - -# qhasm: int128 x0x1x10x11 - -# qhasm: int128 x12x13x6x7 - -# qhasm: int128 x8x9x2x3 - -# qhasm: int128 x4x5x14x15 - -# qhasm: int128 x0x1x2x3 - -# qhasm: int128 x4x5x6x7 - -# qhasm: int128 x8x9x10x11 - -# qhasm: int128 x12x13x14x15 - -# qhasm: int128 m0m1m2m3 - -# qhasm: int128 m4m5m6m7 - -# qhasm: int128 m8m9m10m11 - -# qhasm: int128 m12m13m14m15 - -# qhasm: int128 start0 - -# qhasm: int128 start1 - -# qhasm: int128 start2 - -# qhasm: int128 start3 - -# qhasm: stack128 stack_start3 - -# qhasm: stack128 next_start2 - -# qhasm: stack128 next_start3 - -# qhasm: int128 k0k1k2k3 - -# qhasm: int128 k4k5k6k7 - -# qhasm: int128 k1n1k7k2 - -# qhasm: int128 n2n3n3n2 - -# qhasm: int128 k2k3k6k7 - -# qhasm: int128 nextblock - -# qhasm: stack128 stack_q4 - -# qhasm: stack128 stack_q5 - -# qhasm: stack128 stack_q6 - -# qhasm: stack128 stack_q7 - -# qhasm: stack32 stack_r4 - -# qhasm: stack128 k2k3k6k7_stack - -# qhasm: stack128 k1n1k7k2_stack - -# qhasm: stack512 tmp - -# qhasm: stack32 savec - -# qhasm: int32 i - -# qhasm: int32 ci - -# qhasm: int32 mi - -# qhasm: enter zt_salsa2012_armneon3_xor -.align 2 -.global _zt_salsa2012_armneon3_xor -.global zt_salsa2012_armneon3_xor -.type _zt_salsa2012_armneon3_xor STT_FUNC -.type zt_salsa2012_armneon3_xor STT_FUNC -_zt_salsa2012_armneon3_xor: -zt_salsa2012_armneon3_xor: -sub sp,sp,#256 - -# qhasm: new stack_q4 - -# qhasm: new stack_q5 - -# qhasm: new stack_q6 - -# qhasm: new stack_q7 - -# qhasm: stack_q4 bot = caller_q4 bot -# asm 1: vstr stack_r4=stack32#2 -# asm 2: str stack_r4=[sp,#68] -str r4,[sp,#68] - -# qhasm: int32 c - -# qhasm: c = input_0 -# asm 1: mov >c=int32#1,c=r0,m=int32#2,m=r1,mlenlow=int32#3,mlenlow=r2,mlenhigh=int32#4,mlenhigh=r3,n=int32#5,n=r4,k=int32#13,k=r12,k0k1k2k3=reg128#1%bot->k0k1k2k3=reg128#1%top},[k0k1k2k3=d0->k0k1k2k3=d1},[k4k5k6k7=reg128#2%bot->k4k5k6k7=reg128#2%top},[k4k5k6k7=d2->k4k5k6k7=d3},[i=int32#13,=sigma -# asm 2: ldr >i=r12,=sigma -ldr r12,=sigma - -# qhasm: start0 = mem128[i] -# asm 1: vld1.8 {>start0=reg128#3%bot->start0=reg128#3%top},[start0=d4->start0=d5},[start1=reg128#4,#0 -# asm 2: vmov.i64 >start1=q3,#0 -vmov.i64 q3,#0 - -# qhasm: start1 bot = mem64[n] -# asm 1: vld1.8 {k2k3k6k7=reg128#6,k2k3k6k7=q5,n2n3n3n2=reg128#1,#0 -# asm 2: vmov.i64 >n2n3n3n2=q0,#0 -vmov.i64 q0,#0 - -# qhasm: unsigneddiag0=reg128#8,diag0=q7,diag1=reg128#9,diag1=q8,start2=reg128#10,start2=q9,nextblock=reg128#11,#0xff -# asm 2: vmov.i64 >nextblock=q10,#0xff -vmov.i64 q10,#0xff - -# qhasm: 4x nextblock unsigned>>= 7 -# asm 1: vshr.u32 >nextblock=reg128#11,nextblock=q10,n2n3n3n2=reg128#1,n2n3n3n2=q0,n2n3n3n2=reg128#1,n2n3n3n2=q0,next_diag0=reg128#2,next_diag0=q1,next_diag1=reg128#5,next_diag1=q4,i=int32#5,=12 -# asm 2: ldr >i=r4,=12 -ldr r4,=12 - -# qhasm: mainloop2: -._mainloop2: - -# qhasm: 4x a0 = diag1 + diag0 -# asm 1: vadd.i32 >a0=reg128#11,a0=q10,next_a0=reg128#14,next_a0=q13,b0=reg128#15,b0=q14,next_b0=reg128#16,next_b0=q15,> 25 -# asm 1: vsri.i32 > 25 -# asm 1: vsri.i32 diag3=reg128#7,diag3=q6,next_diag3=reg128#11,next_diag3=q10,a1=reg128#13,a1=q12,next_a1=reg128#14,next_a1=q13,b1=reg128#15,b1=q14,next_b1=reg128#16,next_b1=q15,> 23 -# asm 1: vsri.i32 > 23 -# asm 1: vsri.i32 diag2=reg128#6,diag2=q5,next_diag2=reg128#12,next_diag2=q11,a2=reg128#13,a2=q12,diag3=reg128#7,diag3=q6,next_a2=reg128#14,next_a2=q13,b2=reg128#15,b2=q14,next_diag3=reg128#11,next_diag3=q10,next_b2=reg128#16,next_b2=q15,> 19 -# asm 1: vsri.i32 > 19 -# asm 1: vsri.i32 diag1=reg128#9,diag1=q8,next_diag1=reg128#5,next_diag1=q4,a3=reg128#13,a3=q12,next_a3=reg128#14,next_a3=q13,b3=reg128#15,b3=q14,next_b3=reg128#16,next_b3=q15,> 14 -# asm 1: vsri.i32 diag1=reg128#9,diag1=q8,> 14 -# asm 1: vsri.i32 diag0=reg128#8,diag0=q7,next_diag1=reg128#5,next_diag1=q4,next_diag0=reg128#2,next_diag0=q1,a0=reg128#13,a0=q12,next_a0=reg128#14,next_a0=q13,b0=reg128#15,b0=q14,next_b0=reg128#16,next_b0=q15,> 25 -# asm 1: vsri.i32 > 25 -# asm 1: vsri.i32 diag1=reg128#9,diag1=q8,next_diag1=reg128#5,next_diag1=q4,a1=reg128#13,a1=q12,next_a1=reg128#14,next_a1=q13,b1=reg128#15,b1=q14,next_b1=reg128#16,next_b1=q15,> 23 -# asm 1: vsri.i32 ? i -= 2 -# asm 1: subs > 23 -# asm 1: vsri.i32 diag2=reg128#6,diag2=q5,next_diag2=reg128#12,next_diag2=q11,a2=reg128#13,a2=q12,diag1=reg128#9,diag1=q8,next_a2=reg128#14,next_a2=q13,b2=reg128#15,b2=q14,next_diag1=reg128#5,next_diag1=q4,next_b2=reg128#16,next_b2=q15,> 19 -# asm 1: vsri.i32 > 19 -# asm 1: vsri.i32 diag3=reg128#7,diag3=q6,next_diag3=reg128#11,next_diag3=q10,a3=reg128#13,a3=q12,next_a3=reg128#14,next_a3=q13,b3=reg128#15,b3=q14,next_b3=reg128#16,next_b3=q15,> 14 -# asm 1: vsri.i32 diag3=reg128#7,diag3=q6,> 14 -# asm 1: vsri.i32 diag0=reg128#8,diag0=q7,next_diag3=reg128#13,next_diag3=q12,next_diag0=reg128#2,next_diag0=q1, -bhi ._mainloop2 - -# qhasm: 2x abab = 0xffffffff -# asm 1: vmov.i64 >abab=reg128#11,#0xffffffff -# asm 2: vmov.i64 >abab=q10,#0xffffffff -vmov.i64 q10,#0xffffffff - -# qhasm: new x4x9x14x3 - -# qhasm: x4x9x14x3 bot = stack_start3 bot -# asm 1: vldr x0x5x10x15=reg128#8,x0x5x10x15=q7,x12x1x6x11=reg128#9,x12x1x6x11=q8,x8x13x2x7=reg128#6,x8x13x2x7=q5,x4x9x14x3=reg128#7,x4x9x14x3=q6,x0x1x10x11=reg128#10,x0x1x10x11=q9,x12x13x6x7=reg128#14,x12x13x6x7=q13,x8x9x2x3=reg128#15,x8x9x2x3=q14,x4x5x14x15=reg128#16,x4x5x14x15=q15,x0x1x2x3=reg128#6,x0x1x2x3=q5,x4x5x6x7=reg128#7,x4x5x6x7=q6,x8x9x10x11=reg128#8,x8x9x10x11=q7,x12x13x14x15=reg128#9,x12x13x14x15=q8,m0m1m2m3=reg128#10%bot->m0m1m2m3=reg128#10%top},[m0m1m2m3=d18->m0m1m2m3=d19},[m4m5m6m7=reg128#14%bot->m4m5m6m7=reg128#14%top},[m4m5m6m7=d26->m4m5m6m7=d27},[m8m9m10m11=reg128#15%bot->m8m9m10m11=reg128#15%top},[m8m9m10m11=d28->m8m9m10m11=d29},[m12m13m14m15=reg128#16%bot->m12m13m14m15=reg128#16%top},[m12m13m14m15=d30->m12m13m14m15=d31},[x0x1x2x3=reg128#6,x0x1x2x3=q5,x4x5x6x7=reg128#7,x4x5x6x7=q6,x8x9x10x11=reg128#8,x8x9x10x11=q7,x12x13x14x15=reg128#9,x12x13x14x15=q8,x0x5x10x15=reg128#2,x0x5x10x15=q1,x12x1x6x11=reg128#5,x12x1x6x11=q4,x8x13x2x7=reg128#6,x8x13x2x7=q5,x4x9x14x3=reg128#7,x4x9x14x3=q6,x0x1x10x11=reg128#8,x0x1x10x11=q7,x12x13x6x7=reg128#9,x12x13x6x7=q8,x8x9x2x3=reg128#10,x8x9x2x3=q9,x4x5x14x15=reg128#12,x4x5x14x15=q11,x0x1x2x3=reg128#2,x0x1x2x3=q1,x4x5x6x7=reg128#5,x4x5x6x7=q4,x8x9x10x11=reg128#6,x8x9x10x11=q5,x12x13x14x15=reg128#7,x12x13x14x15=q6,m0m1m2m3=reg128#8%bot->m0m1m2m3=reg128#8%top},[m0m1m2m3=d14->m0m1m2m3=d15},[m4m5m6m7=reg128#9%bot->m4m5m6m7=reg128#9%top},[m4m5m6m7=d16->m4m5m6m7=d17},[m8m9m10m11=reg128#10%bot->m8m9m10m11=reg128#10%top},[m8m9m10m11=d18->m8m9m10m11=d19},[m12m13m14m15=reg128#11%bot->m12m13m14m15=reg128#11%top},[m12m13m14m15=d20->m12m13m14m15=d21},[x0x1x2x3=reg128#2,x0x1x2x3=q1,x4x5x6x7=reg128#5,x4x5x6x7=q4,x8x9x10x11=reg128#6,x8x9x10x11=q5,x12x13x14x15=reg128#7,x12x13x14x15=q6,? mlenhigh - 0 -# asm 1: cmp -bhi ._mlenatleast128 - -# qhasm: =? mlenlow - 0 -# asm 1: cmp savec=stack32#1 -# asm 2: str savec=[sp,#64] -str r0,[sp,#64] - -# qhasm: c = &tmp -# asm 1: lea >c=int32#1,c=r0,i=int32#4,=0 -# asm 2: ldr >i=r3,=0 -ldr r3,=0 - -# qhasm: mcopy: -._mcopy: - -# qhasm: mi = mem8[m + 0] -# asm 1: ldrb >mi=int32#5,[mi=r4,[mi=int32#2,=0 -# asm 2: ldr >mi=r1,=0 -ldr r1,=0 - -# qhasm: pad: -._pad: - -# qhasm: mem8[c + 0] = mi -# asm 1: strb m=int32#2,m=r1,diag0=reg128#2,diag0=q1,diag1=reg128#5,diag1=q4,diag2=reg128#8,diag2=q7,diag3=reg128#9,diag3=q8,nextblock=reg128#10,#0xff -# asm 2: vmov.i64 >nextblock=q9,#0xff -vmov.i64 q9,#0xff - -# qhasm: 4x nextblock unsigned>>= 7 -# asm 1: vshr.u32 >nextblock=reg128#10,nextblock=q9,n2n3n3n2=reg128#1,n2n3n3n2=q0,i=int32#4,=12 -# asm 2: ldr >i=r3,=12 -ldr r3,=12 - -# qhasm: mainloop1: -._mainloop1: - -# qhasm: 4x a0 = diag1 + diag0 -# asm 1: vadd.i32 >a0=reg128#10,a0=q9,b0=reg128#11,b0=q10,> 25 -# asm 1: vsri.i32 diag3=reg128#9,diag3=q8,a1=reg128#10,a1=q9,b1=reg128#11,b1=q10,> 23 -# asm 1: vsri.i32 diag2=reg128#8,diag2=q7,a2=reg128#10,a2=q9,diag3=reg128#9,diag3=q8,b2=reg128#11,b2=q10,> 19 -# asm 1: vsri.i32 diag1=reg128#5,diag1=q4,a3=reg128#10,a3=q9,b3=reg128#11,b3=q10,> 14 -# asm 1: vsri.i32 diag1=reg128#5,diag1=q4,diag0=reg128#2,diag0=q1,a0=reg128#10,a0=q9,b0=reg128#11,b0=q10,> 25 -# asm 1: vsri.i32 diag1=reg128#5,diag1=q4,a1=reg128#10,a1=q9,b1=reg128#11,b1=q10,> 23 -# asm 1: vsri.i32 ? i -= 2 -# asm 1: subs diag2=reg128#8,diag2=q7,a2=reg128#10,a2=q9,diag1=reg128#5,diag1=q4,b2=reg128#11,b2=q10,> 19 -# asm 1: vsri.i32 diag3=reg128#9,diag3=q8,a3=reg128#10,a3=q9,b3=reg128#11,b3=q10,> 14 -# asm 1: vsri.i32 diag3=reg128#9,diag3=q8,diag0=reg128#2,diag0=q1, -bhi ._mainloop1 - -# qhasm: 2x abab = 0xffffffff -# asm 1: vmov.i64 >abab=reg128#10,#0xffffffff -# asm 2: vmov.i64 >abab=q9,#0xffffffff -vmov.i64 q9,#0xffffffff - -# qhasm: 4x x0x5x10x15 = diag0 + start0 -# asm 1: vadd.i32 >x0x5x10x15=reg128#2,x0x5x10x15=q1,x12x1x6x11=reg128#5,x12x1x6x11=q4,x8x13x2x7=reg128#6,x8x13x2x7=q5,x4x9x14x3=reg128#7,x4x9x14x3=q6,x0x1x10x11=reg128#8,x0x1x10x11=q7,x12x13x6x7=reg128#9,x12x13x6x7=q8,x8x9x2x3=reg128#11,x8x9x2x3=q10,x4x5x14x15=reg128#12,x4x5x14x15=q11,x0x1x2x3=reg128#2,x0x1x2x3=q1,x4x5x6x7=reg128#5,x4x5x6x7=q4,x8x9x10x11=reg128#6,x8x9x10x11=q5,x12x13x14x15=reg128#7,x12x13x14x15=q6,m0m1m2m3=reg128#8%bot->m0m1m2m3=reg128#8%top},[m0m1m2m3=d14->m0m1m2m3=d15},[m4m5m6m7=reg128#9%bot->m4m5m6m7=reg128#9%top},[m4m5m6m7=d16->m4m5m6m7=d17},[m8m9m10m11=reg128#10%bot->m8m9m10m11=reg128#10%top},[m8m9m10m11=d18->m8m9m10m11=d19},[m12m13m14m15=reg128#11%bot->m12m13m14m15=reg128#11%top},[m12m13m14m15=d20->m12m13m14m15=d21},[x0x1x2x3=reg128#2,x0x1x2x3=q1,x4x5x6x7=reg128#5,x4x5x6x7=q4,x8x9x10x11=reg128#6,x8x9x10x11=q5,x12x13x14x15=reg128#7,x12x13x14x15=q6,i=int32#4,=0 -# asm 2: ldr >i=r3,=0 -ldr r3,=0 - -# qhasm: m = c - 64 -# asm 1: sub >m=int32#2,m=r1,c=int32#1,c=r0,ci=int32#5,[ci=r4,[? mlenlow -= 64 -# asm 1: subs -bhi ._mlenatleast1 - -# qhasm: done: -._done: - -# qhasm: new caller_r4 - -# qhasm: caller_r4 = stack_r4 -# asm 1: ldr >caller_r4=int32#5,caller_r4=r4,result=int32#1,=0 -# asm 2: ldr >result=r0,=0 -ldr r0,=0 - -# qhasm: return result -add sp,sp,#256 -bx lr diff --git a/ext/bin/tap-mac/tap.kext/Contents/Info.plist b/ext/bin/tap-mac/tap.kext/Contents/Info.plist new file mode 100644 index 00000000..c20eefa5 --- /dev/null +++ b/ext/bin/tap-mac/tap.kext/Contents/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + tap + CFBundleIdentifier + com.zerotier.tap + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + tap + CFBundlePackageType + KEXT + CFBundleShortVersionString + 20150118 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + OSBundleLibraries + + com.apple.kpi.mach + 8.0 + com.apple.kpi.bsd + 8.0 + com.apple.kpi.libkern + 8.0 + com.apple.kpi.unsupported + 8.0 + + + + diff --git a/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap b/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap new file mode 100755 index 00000000..48bf9625 Binary files /dev/null and b/ext/bin/tap-mac/tap.kext/Contents/MacOS/tap differ diff --git a/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources b/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources new file mode 100644 index 00000000..0710b400 --- /dev/null +++ b/ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources @@ -0,0 +1,105 @@ + + + + + files + + files2 + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/ext/bin/tap-windows-ndis6/arm64/zttap300.cat b/ext/bin/tap-windows-ndis6/arm64/zttap300.cat deleted file mode 100644 index 906a15a4..00000000 Binary files a/ext/bin/tap-windows-ndis6/arm64/zttap300.cat and /dev/null differ diff --git a/ext/bin/tap-windows-ndis6/arm64/zttap300.inf b/ext/bin/tap-windows-ndis6/arm64/zttap300.inf deleted file mode 100644 index 8e74daab..00000000 --- a/ext/bin/tap-windows-ndis6/arm64/zttap300.inf +++ /dev/null @@ -1,145 +0,0 @@ -; -; **************************************************************************** -; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * -; * This program is free software; you can redistribute it and/or modify * -; * it under the terms of the GNU General Public License version 2 * -; * as published by the Free Software Foundation. * -; **************************************************************************** -; - -; -; ZeroTier One Virtual Network Port NDIS6 Driver -; -; Modified by ZeroTier, Inc. - https://www.zerotier.com/ -; -; (1) Comment out 'tun' functionality and related features such as DHCP -; emulation, since we don't use any of that. Just want straight 'tap'. -; (2) Added custom IOCTL to enumerate L2 multicast memberships. -; (3) Increase maximum number of multicast memberships to 128. -; (4) Set default and max device MTU to 2800. -; (5) Rename/rebrand driver as ZeroTier network port driver. -; -; Original copyright below. Modifications released under GPLv2 as well. - -[Version] -Signature = "$Windows NT$" -CatalogFile = zttap300.cat -ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} -Provider = %Provider% -Class = Net -DriverVer=11/24/2020,3.00.00.1 - -[Strings] -DeviceDescription = "ZeroTier Virtual Port" -Provider = "ZeroTier" - -[Manufacturer] -%Provider%=zttap300,NTx86 -%Provider%=zttap300,NTamd64 -%Provider%=zttap300,NTarm64 - -[zttap300.NTx86] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -[zttap300.NTamd64] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -[zttap300.NTarm64] -%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated -%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy - -;----------------- Characteristics ------------ -; NCF_PHYSICAL = 0x04 -; NCF_VIRTUAL = 0x01 -; NCF_SOFTWARE_ENUMERATED = 0x02 -; NCF_HIDDEN = 0x08 -; NCF_NO_SERVICE = 0x10 -; NCF_HAS_UI = 0x80 -;----------------- Characteristics ------------ -[zttap300.ndi] -CopyFiles = zttap300.driver, zttap300.files -AddReg = zttap300.reg -AddReg = zttap300.params.reg -Characteristics = 0x81 -*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD -*MediaType = 0x0 ; NdisMedium802_3 -*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 - -[zttap300.ndi.Services] -AddService = zttap300, 2, zttap300.service - -[zttap300.reg] -HKR, Ndi, Service, 0, "zttap300" -HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows. -HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" -HKR, , Manufacturer, 0, "%Provider%" -HKR, , ProductName, 0, "%DeviceDescription%" - -[zttap300.params.reg] -HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" -HKR, Ndi\params\MTU, Type, 0, "int" -HKR, Ndi\params\MTU, Default, 0, "2800" -HKR, Ndi\params\MTU, Optional, 0, "0" -HKR, Ndi\params\MTU, Min, 0, "100" -HKR, Ndi\params\MTU, Max, 0, "2800" -HKR, Ndi\params\MTU, Step, 0, "1" -HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" -HKR, Ndi\params\MediaStatus, Type, 0, "enum" -HKR, Ndi\params\MediaStatus, Default, 0, "0" -HKR, Ndi\params\MediaStatus, Optional, 0, "0" -HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" -HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" -HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address" -HKR, Ndi\params\MAC, Type, 0, "edit" -HKR, Ndi\params\MAC, Optional, 0, "1" -HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" -HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" -HKR, Ndi\params\AllowNonAdmin, Default, 0, "0" -HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" -HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" -HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" - -;---------- Service Type ------------- -; SERVICE_KERNEL_DRIVER = 0x01 -; SERVICE_WIN32_OWN_PROCESS = 0x10 -;---------- Service Type ------------- - -;---------- Start Mode --------------- -; SERVICE_BOOT_START = 0x0 -; SERVICE_SYSTEM_START = 0x1 -; SERVICE_AUTO_START = 0x2 -; SERVICE_DEMAND_START = 0x3 -; SERVICE_DISABLED = 0x4 -;---------- Start Mode --------------- - -[zttap300.service] -DisplayName = %DeviceDescription% -ServiceType = 1 -StartType = 3 -ErrorControl = 1 -LoadOrderGroup = NDIS -ServiceBinary = %12%\zttap300.sys - -;----------------- Copy Flags ------------ -; COPYFLG_NOSKIP = 0x02 -; COPYFLG_NOVERSIONCHECK = 0x04 -;----------------- Copy Flags ------------ - -[SourceDisksNames] -1 = %DeviceDescription%, zttap300.sys - -[SourceDisksFiles] -zttap300.sys = 1 - -[DestinationDirs] -zttap300.files = 11 -zttap300.driver = 12 - -[zttap300.files] -; - -[zttap300.driver] -zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK - diff --git a/ext/bin/tap-windows-ndis6/arm64/zttap300.sys b/ext/bin/tap-windows-ndis6/arm64/zttap300.sys deleted file mode 100644 index ae1a16f4..00000000 Binary files a/ext/bin/tap-windows-ndis6/arm64/zttap300.sys and /dev/null differ diff --git a/ext/bin/tap-windows-ndis6/certutil.exe b/ext/bin/tap-windows-ndis6/certutil.exe new file mode 100644 index 00000000..b9a0a09c Binary files /dev/null and b/ext/bin/tap-windows-ndis6/certutil.exe differ diff --git a/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi b/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi new file mode 100644 index 00000000..17fe08c2 Binary files /dev/null and b/ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi differ diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.cat b/ext/bin/tap-windows-ndis6/x64/zttap300.cat index 6eef79ff..8b9114c7 100644 Binary files a/ext/bin/tap-windows-ndis6/x64/zttap300.cat and b/ext/bin/tap-windows-ndis6/x64/zttap300.cat differ diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.inf b/ext/bin/tap-windows-ndis6/x64/zttap300.inf index e05038da..453797b3 100644 --- a/ext/bin/tap-windows-ndis6/x64/zttap300.inf +++ b/ext/bin/tap-windows-ndis6/x64/zttap300.inf @@ -30,11 +30,11 @@ CatalogFile = zttap300.cat ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} Provider = %Provider% Class = Net -DriverVer=11/24/2020,3.00.00.1 +DriverVer=08/13/2015,6.2.9200.20557 [Strings] -DeviceDescription = "ZeroTier Virtual Port" -Provider = "ZeroTier" +DeviceDescription = "ZeroTier One Virtual Port" +Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. ; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! [Manufacturer] @@ -141,4 +141,3 @@ zttap300.driver = 12 [zttap300.driver] zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK - diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.sys b/ext/bin/tap-windows-ndis6/x64/zttap300.sys index 2c7922b3..3d846a53 100644 Binary files a/ext/bin/tap-windows-ndis6/x64/zttap300.sys and b/ext/bin/tap-windows-ndis6/x64/zttap300.sys differ diff --git a/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi b/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi new file mode 100644 index 00000000..415774c9 Binary files /dev/null and b/ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi differ diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.cat b/ext/bin/tap-windows-ndis6/x86/zttap300.cat index f6021aa8..44347f54 100644 Binary files a/ext/bin/tap-windows-ndis6/x86/zttap300.cat and b/ext/bin/tap-windows-ndis6/x86/zttap300.cat differ diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.inf b/ext/bin/tap-windows-ndis6/x86/zttap300.inf index a562e9d6..453797b3 100644 --- a/ext/bin/tap-windows-ndis6/x86/zttap300.inf +++ b/ext/bin/tap-windows-ndis6/x86/zttap300.inf @@ -1,15 +1,10 @@ -; -; **************************************************************************** -; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * -; * This program is free software; you can redistribute it and/or modify * -; * it under the terms of the GNU General Public License version 2 * -; * as published by the Free Software Foundation. * -; **************************************************************************** -; - ; ; ZeroTier One Virtual Network Port NDIS6 Driver ; +; Based on the OpenVPN tap-windows6 driver version 9.21.1 git +; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3. +; See: https://github.com/OpenVPN/tap-windows6 +; ; Modified by ZeroTier, Inc. - https://www.zerotier.com/ ; ; (1) Comment out 'tun' functionality and related features such as DHCP @@ -20,6 +15,14 @@ ; (5) Rename/rebrand driver as ZeroTier network port driver. ; ; Original copyright below. Modifications released under GPLv2 as well. +; +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** +; [Version] Signature = "$Windows NT$" @@ -27,17 +30,17 @@ CatalogFile = zttap300.cat ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} Provider = %Provider% Class = Net -DriverVer=11/24/2020,3.00.00.1 +DriverVer=08/13/2015,6.2.9200.20557 [Strings] -DeviceDescription = "ZeroTier Virtual Port" -Provider = "ZeroTier" +DeviceDescription = "ZeroTier One Virtual Port" +Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat. +; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back! [Manufacturer] -%Provider%=zttap300,NTx86 -;%Provider%=zttap300,NTamd64 +%Provider%=zttap300,NTamd64 -[zttap300.NTx86] +[zttap300] %DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated %DeviceDescription% = zttap300.ndi, zttap300 ; Legacy @@ -138,4 +141,3 @@ zttap300.driver = 12 [zttap300.driver] zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK - diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.sys b/ext/bin/tap-windows-ndis6/x86/zttap300.sys index 86e51a3e..664398e9 100644 Binary files a/ext/bin/tap-windows-ndis6/x86/zttap300.sys and b/ext/bin/tap-windows-ndis6/x86/zttap300.sys differ diff --git a/ext/bin/tap-windows-ndis6/zttap300.cer b/ext/bin/tap-windows-ndis6/zttap300.cer new file mode 100644 index 00000000..ef74e041 Binary files /dev/null and b/ext/bin/tap-windows-ndis6/zttap300.cer differ diff --git a/ext/central-controller-docker/Dockerfile b/ext/central-controller-docker/Dockerfile index c134cbdc..2fc92e6f 100644 --- a/ext/central-controller-docker/Dockerfile +++ b/ext/central-controller-docker/Dockerfile @@ -1,15 +1,19 @@ # Dockerfile for ZeroTier Central Controllers -FROM registry.zerotier.com/zerotier/ctlbuild:latest as builder +FROM centos:7 MAINTAINER Adam Ierymekno , Grant Limberg -ADD . /ZeroTierOne -RUN export PATH=$PATH:~/.cargo/bin && cd ZeroTierOne && make clean && make central-controller -j8 -FROM registry.zerotier.com/zerotier/ctlrun:latest -COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one +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 -RUN echo "/usr/local/lib64" > /etc/ld.so.conf.d/usr-local-lib64.conf && ldconfig -ADD ext/central-controller-docker/main.sh / +ADD docker/main.sh / RUN chmod a+x /main.sh ENTRYPOINT /main.sh diff --git a/ext/central-controller-docker/Dockerfile.builder b/ext/central-controller-docker/Dockerfile.builder deleted file mode 100644 index 29356b8e..00000000 --- a/ext/central-controller-docker/Dockerfile.builder +++ /dev/null @@ -1,26 +0,0 @@ -# Dockerfile for building ZeroTier Central Controllers -FROM ubuntu:jammy as builder -MAINTAINER Adam Ierymekno , Grant Limberg - -ARG git_branch=master - -RUN apt update && apt upgrade -y -RUN apt -y install \ - build-essential \ - pkg-config \ - bash \ - clang \ - libjemalloc2 \ - libjemalloc-dev \ - libpq5 \ - libpq-dev \ - openssl \ - libssl-dev \ - postgresql-client \ - postgresql-client-common \ - curl \ - google-perftools \ - libgoogle-perftools-dev \ - protobuf-compiler - -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y diff --git a/ext/central-controller-docker/Dockerfile.run_base b/ext/central-controller-docker/Dockerfile.run_base deleted file mode 100644 index a581d015..00000000 --- a/ext/central-controller-docker/Dockerfile.run_base +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:jammy - -RUN apt update && apt upgrade -y - -RUN apt -y install \ - netcat \ - postgresql-client \ - postgresql-client-common \ - libjemalloc2 \ - libpq5 \ - curl \ - binutils \ - linux-tools-gke \ - perf-tools-unstable \ - google-perftools diff --git a/ext/central-controller-docker/Makefile b/ext/central-controller-docker/Makefile deleted file mode 100644 index 46ec8ee1..00000000 --- a/ext/central-controller-docker/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -registry = registry.zerotier.com/zerotier - -all: controller-builder controller-runbase - -buildx: - @echo "docker buildx create" - # docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --privileged --rm tonistiigi/binfmt --install all - @echo docker buildx create --name multiarch --driver docker-container --use - @echo docker buildx inspect --bootstrap - -controller-builder: buildx - docker buildx build --no-cache --platform linux/amd64,linux/arm64 -t $(registry)/ctlbuild:latest -f Dockerfile.builder . --push - -controller-runbase: buildx - docker buildx build --no-cache --platform linux/amd64,linux/arm64 -t $(registry)/ctlrun:latest -f Dockerfile.run_base . --push diff --git a/ext/central-controller-docker/main.sh b/ext/central-controller-docker/main.sh index 5583b3ad..b8d3b142 100755 --- a/ext/central-controller-docker/main.sh +++ b/ext/central-controller-docker/main.sh @@ -25,32 +25,30 @@ if [ -z "$ZT_DB_PASSWORD" ]; then exit 1 fi -REDIS="" -if [ "$ZT_USE_REDIS" == "true" ]; then - if [ -z "$ZT_REDIS_HOST" ]; then - echo '*** FAILED: ZT_REDIS_HOST environment variable not defined' +RMQ="" +if [ "$ZT_USE_RABBITMQ" == "true" ]; then + if [ -z "$RABBITMQ_HOST" ]; then + echo '*** FAILED: RABBITMQ_HOST environment variable not defined' exit 1 fi - - if [ -z "$ZT_REDIS_PORT" ]; then - echo '*** FAILED: ZT_REDIS_PORT enivronment variable not defined' + if [ -z "$RABBITMQ_PORT" ]; then + echo '*** FAILED: RABBITMQ_PORT environment variable not defined' exit 1 fi - - if [ -z "$ZT_REDIS_CLUSTER_MODE" ]; then - echo '*** FAILED: ZT_REDIS_CLUSTER_MODE environment variable not defined' + if [ -z "$RABBITMQ_USERNAME" ]; then + echo '*** FAILED: RABBITMQ_USERNAME environment variable not defined' exit 1 fi - - REDIS="\"redis\": { - \"hostname\": \"${ZT_REDIS_HOST}\", - \"port\": ${ZT_REDIS_PORT}, - \"clusterMode\": ${ZT_REDIS_CLUSTER_MODE}, - \"password\": \"${ZT_REDIS_PASSWORD}\" - } - " -else - REDIS="\"redis\": null" + if [ -z "$RABBITMQ_PASSWORD" ]; then + echo '*** FAILED: RABBITMQ_PASSWORD environment variable not defined' + exit 1 + fi + RMQ=", \"rabbitmq\": { + \"host\": \"${RABBITMQ_HOST}\", + \"port\": ${RABBITMQ_PORT}, + \"username\": \"${RABBITMQ_USERNAME}\", + \"password\": \"${RABBITMQ_PASSWORD}\" + }" fi mkdir -p /var/lib/zerotier-one @@ -58,58 +56,25 @@ mkdir -p /var/lib/zerotier-one pushd /var/lib/zerotier-one ln -s $ZT_IDENTITY_PATH/identity.public identity.public ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret -if [ -f "$ZT_IDENTITY_PATH/authtoken.secret" ]; then - ln -s $ZT_IDENTITY_PATH/authtoken.secret authtoken.secret -fi popd DEFAULT_PORT=9993 -DEFAULT_LB_MODE=false - -APP_NAME="controller-$(cat /var/lib/zerotier-one/identity.public | cut -d ':' -f 1)" echo "{ \"settings\": { - \"controllerDbPath\": \"postgres:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} application_name=${APP_NAME} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\", \"portMappingEnabled\": true, \"softwareUpdate\": \"disable\", \"interfacePrefixBlacklist\": [ \"inot\", \"nat64\" ], - \"lowBandwidthMode\": ${ZT_LB_MODE:-$DEFAULT_LB_MODE}, - \"ssoRedirectURL\": \"${ZT_SSO_REDIRECT_URL}\", - \"allowManagementFrom\": [\"127.0.0.1\", \"::1\", \"10.0.0.0/8\"], - ${REDIS} + \"controllerDbPath\": \"postgres:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\" + ${RMQ} } } " > /var/lib/zerotier-one/local.conf -if [ -n "$DB_SERVER_CA" ]; then - echo "secret list" - chmod 600 /secrets/db/*.pem - ls -l /secrets/db/ - until /usr/bin/pg_isready -h ${ZT_DB_HOST} -p ${ZT_DB_PORT} -d "sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}"; do - echo "Waiting for PostgreSQL..."; - sleep 2; - done -else - until /usr/bin/pg_isready -h ${ZT_DB_HOST} -p ${ZT_DB_PORT}; do - echo "Waiting for PostgreSQL..."; - sleep 2; - done -fi - -if [ -n "$ZT_TEMPORAL_HOST" ] && [ -n "$ZT_TEMPORAL_PORT" ]; then - echo "waiting for temporal..." - while ! nc -z ${ZT_TEMPORAL_HOST} ${ZT_TEMPORAL_PORT}; do - echo "waiting..."; - sleep 1; - done - echo "Temporal is up" -fi - export GLIBCXX_FORCE_NEW=1 export GLIBCPP_FORCE_NEW=1 -export LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libjemalloc.so.2" +export LD_PRELOAD="/usr/lib64/libjemalloc.so" exec /usr/local/bin/zerotier-one -p${ZT_CONTROLLER_PORT:-$DEFAULT_PORT} /var/lib/zerotier-one diff --git a/ext/inja/LICENSE b/ext/cpp-httplib/LICENSE similarity index 95% rename from ext/inja/LICENSE rename to ext/cpp-httplib/LICENSE index 9e06bea0..3e5ed359 100644 --- a/ext/inja/LICENSE +++ b/ext/cpp-httplib/LICENSE @@ -1,6 +1,6 @@ -MIT License +The MIT License (MIT) -Copyright (c) 2018-2021 Berscheid +Copyright (c) 2017 yhirose Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,3 +19,4 @@ 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. + diff --git a/ext/cpp-httplib/README.md b/ext/cpp-httplib/README.md new file mode 100644 index 00000000..2bd23454 --- /dev/null +++ b/ext/cpp-httplib/README.md @@ -0,0 +1,259 @@ +cpp-httplib +=========== + +[![Build Status](https://travis-ci.org/yhirose/cpp-httplib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-httplib) +[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-httplib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-httplib) + +A C++ header-only cross platform HTTP/HTTPS library. + +It's extremely easy to setup. Just include **httplib.h** file in your code! + +Inspired by [Sinatra](http://www.sinatrarb.com/) and [express](https://github.com/visionmedia/express). + +Server Example +-------------- + +```c++ +#include + +int main(void) +{ + using namespace httplib; + + Server svr; + + svr.Get("/hi", [](const Request& req, Response& res) { + res.set_content("Hello World!", "text/plain"); + }); + + svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) { + auto numbers = req.matches[1]; + res.set_content(numbers, "text/plain"); + }); + + svr.listen("localhost", 1234); +} +``` + +`Post`, `Put`, `Delete` and `Options` methods are also supported. + +### Bind a socket to multiple interfaces and any available port + +```cpp +int port = svr.bind_to_any_port("0.0.0.0"); +svr.listen_after_bind(); +``` + +### Method Chain + +```cpp +svr.Get("/get", [](const auto& req, auto& res) { + res.set_content("get", "text/plain"); + }) + .Post("/post", [](const auto& req, auto& res) { + res.set_content(req.body(), "text/plain"); + }) + .listen("localhost", 1234); +``` + +### Static File Server + +```cpp +svr.set_base_dir("./www"); +``` + +### Logging + +```cpp +svr.set_logger([](const auto& req, const auto& res) { + your_logger(req, res); +}); +``` + +### Error Handler + +```cpp +svr.set_error_handler([](const auto& req, auto& res) { + const char* fmt = "

Error Status: %d

"; + char buf[BUFSIZ]; + snprintf(buf, sizeof(buf), fmt, res.status); + res.set_content(buf, "text/html"); +}); +``` + +### 'multipart/form-data' POST data + +```cpp +svr.Post("/multipart", [&](const auto& req, auto& res) { + auto size = req.files.size(); + auto ret = req.has_file("name1")); + const auto& file = req.get_file_value("name1"); + // file.filename; + // file.content_type; + auto body = req.body.substr(file.offset, file.length)); +}) +``` + +Client Example +-------------- + +### GET + +```c++ +#include +#include + +int main(void) +{ + httplib::Client cli("localhost", 1234); + + auto res = cli.Get("/hi"); + if (res && res->status == 200) { + std::cout << res->body << std::endl; + } +} +``` + +### GET with Content Receiver + +```c++ + std::string body; + auto res = cli.Get("/large-data", [&](const char *data, size_t len) { + body.append(data, len); + }); + assert(res->body.empty()); +``` + +### POST + +```c++ +res = cli.Post("/post", "text", "text/plain"); +res = cli.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); +``` + +### POST with parameters + +```c++ +httplib::Params params; +params.emplace("name", "john"); +params.emplace("note", "coder"); + +auto res = cli.Post("/post", params); +``` + or + +```c++ +httplib::Params params{ + { "name", "john" }, + { "note", "coder" } +}; + +auto res = cli.Post("/post", params); +``` + +### PUT + +```c++ +res = cli.Put("/resource/foo", "text", "text/plain"); +``` + +### DELETE + +```c++ +res = cli.Delete("/resource/foo"); +``` + +### OPTIONS + +```c++ +res = cli.Options("*"); +res = cli.Options("/resource/foo"); +``` + +### Connection Timeout + +```c++ +httplib::Client cli("localhost", 8080, 5); // timeouts in 5 seconds +``` +### With Progress Callback + +```cpp +httplib::Client client(url, port); + +// prints: 0 / 000 bytes => 50% complete +std::shared_ptr res = + cli.Get("/", [](uint64_t len, uint64_t total) { + printf("%lld / %lld bytes => %d%% complete\n", + len, total, + (int)((len/total)*100)); + return true; // return 'false' if you want to cancel the request. + } +); +``` + +![progress](https://user-images.githubusercontent.com/236374/33138910-495c4ecc-cf86-11e7-8693-2fc6d09615c4.gif) + +This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23). + +### Basic Authentication + +```cpp +httplib::Client cli("httplib.org"); + +auto res = cli.Get("/basic-auth/hello/world", { + httplib::make_basic_authentication_header("hello", "world") +}); +// res->status should be 200 +// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n". +``` + +### Range + +```cpp +httplib::Client cli("httpbin.org"); + +auto res = cli.Get("/range/32", { + httplib::make_range_header(1, 10) // 'Range: bytes=1-10' +}); +// res->status should be 206. +// res->body should be "bcdefghijk". +``` + +OpenSSL Support +--------------- + +SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked. + +```c++ +#define CPPHTTPLIB_OPENSSL_SUPPORT + +SSLServer svr("./cert.pem", "./key.pem"); + +SSLClient cli("localhost", 8080); +cli.set_ca_cert_path("./ca-bundle.crt"); +cli.enable_server_certificate_verification(true); +``` + +Zlib Support +------------ + +'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`. + +The server applies gzip compression to the following MIME type contents: + + * all text types + * image/svg+xml + * application/javascript + * application/json + * application/xml + * application/xhtml+xml + +NOTE +---- + +g++ 4.8 cannot build this library since `` in g++4.8 is [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions). + +License +------- + +MIT license (© 2019 Yuji Hirose) diff --git a/ext/cpp-httplib/httplib.h b/ext/cpp-httplib/httplib.h index dfdd260a..5adfc2af 100644 --- a/ext/cpp-httplib/httplib.h +++ b/ext/cpp-httplib/httplib.h @@ -1,126 +1,13 @@ // // httplib.h // -// Copyright (c) 2024 Yuji Hirose. All rights reserved. +// Copyright (c) 2019 Yuji Hirose. All rights reserved. // MIT License // #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_VERSION "0.15.3" - -/* - * Configuration - */ - -#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND -#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5 -#endif - -#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT -#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5 -#endif - -#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND -#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300 -#endif - -#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND -#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0 -#endif - -#ifndef CPPHTTPLIB_READ_TIMEOUT_SECOND -#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5 -#endif - -#ifndef CPPHTTPLIB_READ_TIMEOUT_USECOND -#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0 -#endif - -#ifndef CPPHTTPLIB_WRITE_TIMEOUT_SECOND -#define CPPHTTPLIB_WRITE_TIMEOUT_SECOND 5 -#endif - -#ifndef CPPHTTPLIB_WRITE_TIMEOUT_USECOND -#define CPPHTTPLIB_WRITE_TIMEOUT_USECOND 0 -#endif - -#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND -#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0 -#endif - -#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND -#ifdef _WIN32 -#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000 -#else -#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0 -#endif -#endif - -#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH -#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 -#endif - -#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH -#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192 -#endif - -#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT -#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20 -#endif - -#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT -#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024 -#endif - -#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH -#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits::max)()) -#endif - -#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH -#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192 -#endif - -#ifndef CPPHTTPLIB_RANGE_MAX_COUNT -#define CPPHTTPLIB_RANGE_MAX_COUNT 1024 -#endif - -#ifndef CPPHTTPLIB_TCP_NODELAY -#define CPPHTTPLIB_TCP_NODELAY false -#endif - -#ifndef CPPHTTPLIB_RECV_BUFSIZ -#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u) -#endif - -#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ -#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u) -#endif - -#ifndef CPPHTTPLIB_THREAD_POOL_COUNT -#define CPPHTTPLIB_THREAD_POOL_COUNT \ - ((std::max)(8u, std::thread::hardware_concurrency() > 0 \ - ? std::thread::hardware_concurrency() - 1 \ - : 0)) -#endif - -#ifndef CPPHTTPLIB_RECV_FLAGS -#define CPPHTTPLIB_RECV_FLAGS 0 -#endif - -#ifndef CPPHTTPLIB_SEND_FLAGS -#define CPPHTTPLIB_SEND_FLAGS 0 -#endif - -#ifndef CPPHTTPLIB_LISTEN_BACKLOG -#define CPPHTTPLIB_LISTEN_BACKLOG 5 -#endif - -/* - * Headers - */ - #ifdef _WIN32 #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS @@ -130,26 +17,16 @@ #define _CRT_NONSTDC_NO_DEPRECATE #endif //_CRT_NONSTDC_NO_DEPRECATE -#if defined(_MSC_VER) -#if _MSC_VER < 1900 -#error Sorry, Visual Studio versions prior to 2015 are not supported -#endif - -#pragma comment(lib, "ws2_32.lib") - -#ifdef _WIN64 -using ssize_t = __int64; -#else -using ssize_t = long; -#endif +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf_s #endif // _MSC_VER #ifndef S_ISREG -#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG) +#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG) #endif // S_ISREG #ifndef S_ISDIR -#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR) +#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR) #endif // S_ISDIR #ifndef NOMINMAX @@ -160,689 +37,202 @@ using ssize_t = long; #include #include -#ifndef WSA_FLAG_NO_HANDLE_INHERIT -#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 -#endif +#pragma comment(lib, "ws2_32.lib") -using socket_t = SOCKET; -#ifdef CPPHTTPLIB_USE_POLL -#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout) -#endif - -#else // not _WIN32 +#ifndef strcasecmp +#define strcasecmp _stricmp +#endif // strcasecmp +typedef SOCKET socket_t; +#else #include -#if !defined(_AIX) && !defined(__MVS__) -#include -#endif -#ifdef __MVS__ -#include -#ifndef NI_MAXHOST -#define NI_MAXHOST 1025 -#endif -#endif -#include +#include #include #include -#ifdef __linux__ -#include -#endif -#include -#ifdef CPPHTTPLIB_USE_POLL -#include -#endif -#include #include -#include +#include #include #include -#include #include -using socket_t = int; -#ifndef INVALID_SOCKET +typedef int socket_t; #define INVALID_SOCKET (-1) -#endif #endif //_WIN32 -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include #include #include #include -#include -#include -#include #include #include #include -#include #include -#include -#include #include #include #include -#include -#include -#include #ifdef CPPHTTPLIB_OPENSSL_SUPPORT -#ifdef _WIN32 -#include - -// these are defined in wincrypt.h and it breaks compilation if BoringSSL is -// used -#undef X509_NAME -#undef X509_CERT_PAIR -#undef X509_EXTENSIONS -#undef PKCS7_SIGNER_INFO - -#ifdef _MSC_VER -#pragma comment(lib, "crypt32.lib") -#endif -#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) -#include -#if TARGET_OS_OSX -#include -#include -#endif // TARGET_OS_OSX -#endif // _WIN32 - #include -#include #include #include -#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK) -#include +#if OPENSSL_VERSION_NUMBER < 0x10100000L +inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) { + return M_ASN1_STRING_data(asn1); +} #endif - -#include -#include - -#if OPENSSL_VERSION_NUMBER < 0x30000000L -#error Sorry, OpenSSL versions prior to 3.0.0 are not supported -#endif - #endif #ifdef CPPHTTPLIB_ZLIB_SUPPORT #include #endif -#ifdef CPPHTTPLIB_BROTLI_SUPPORT -#include -#include -#endif - /* - * Declaration + * Configuration */ +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5 +#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0 +#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5 +#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5 +#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0 +#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 +#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (std::numeric_limits::max)() +#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u) + namespace httplib { namespace detail { -/* - * Backport std::make_unique from C++14. - * - * NOTE: This code came up with the following stackoverflow post: - * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique - * - */ - -template -typename std::enable_if::value, std::unique_ptr>::type -make_unique(Args &&...args) { - return std::unique_ptr(new T(std::forward(args)...)); -} - -template -typename std::enable_if::value, std::unique_ptr>::type -make_unique(std::size_t n) { - typedef typename std::remove_extent::type RT; - return std::unique_ptr(new RT[n]); -} - struct ci { bool operator()(const std::string &s1, const std::string &s2) const { - return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), - s2.end(), - [](unsigned char c1, unsigned char c2) { - return ::tolower(c1) < ::tolower(c2); - }); + return std::lexicographical_compare( + s1.begin(), s1.end(), s2.begin(), s2.end(), + [](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); }); } }; -// This is based on -// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189". - -struct scope_exit { - explicit scope_exit(std::function &&f) - : exit_function(std::move(f)), execute_on_destruction{true} {} - - scope_exit(scope_exit &&rhs) noexcept - : exit_function(std::move(rhs.exit_function)), - execute_on_destruction{rhs.execute_on_destruction} { - rhs.release(); - } - - ~scope_exit() { - if (execute_on_destruction) { this->exit_function(); } - } - - void release() { this->execute_on_destruction = false; } - -private: - scope_exit(const scope_exit &) = delete; - void operator=(const scope_exit &) = delete; - scope_exit &operator=(scope_exit &&) = delete; - - std::function exit_function; - bool execute_on_destruction; -}; - } // namespace detail -enum StatusCode { - // Information responses - Continue_100 = 100, - SwitchingProtocol_101 = 101, - Processing_102 = 102, - EarlyHints_103 = 103, +enum class HttpVersion { v1_0 = 0, v1_1 }; - // Successful responses - OK_200 = 200, - Created_201 = 201, - Accepted_202 = 202, - NonAuthoritativeInformation_203 = 203, - NoContent_204 = 204, - ResetContent_205 = 205, - PartialContent_206 = 206, - MultiStatus_207 = 207, - AlreadyReported_208 = 208, - IMUsed_226 = 226, +typedef std::multimap Headers; - // Redirection messages - MultipleChoices_300 = 300, - MovedPermanently_301 = 301, - Found_302 = 302, - SeeOther_303 = 303, - NotModified_304 = 304, - UseProxy_305 = 305, - unused_306 = 306, - TemporaryRedirect_307 = 307, - PermanentRedirect_308 = 308, +template +std::pair make_range_header(uint64_t value, + Args... args); - // Client error responses - BadRequest_400 = 400, - Unauthorized_401 = 401, - PaymentRequired_402 = 402, - Forbidden_403 = 403, - NotFound_404 = 404, - MethodNotAllowed_405 = 405, - NotAcceptable_406 = 406, - ProxyAuthenticationRequired_407 = 407, - RequestTimeout_408 = 408, - Conflict_409 = 409, - Gone_410 = 410, - LengthRequired_411 = 411, - PreconditionFailed_412 = 412, - PayloadTooLarge_413 = 413, - UriTooLong_414 = 414, - UnsupportedMediaType_415 = 415, - RangeNotSatisfiable_416 = 416, - ExpectationFailed_417 = 417, - ImATeapot_418 = 418, - MisdirectedRequest_421 = 421, - UnprocessableContent_422 = 422, - Locked_423 = 423, - FailedDependency_424 = 424, - TooEarly_425 = 425, - UpgradeRequired_426 = 426, - PreconditionRequired_428 = 428, - TooManyRequests_429 = 429, - RequestHeaderFieldsTooLarge_431 = 431, - UnavailableForLegalReasons_451 = 451, +typedef std::multimap Params; +typedef std::smatch Match; - // Server error responses - InternalServerError_500 = 500, - NotImplemented_501 = 501, - BadGateway_502 = 502, - ServiceUnavailable_503 = 503, - GatewayTimeout_504 = 504, - HttpVersionNotSupported_505 = 505, - VariantAlsoNegotiates_506 = 506, - InsufficientStorage_507 = 507, - LoopDetected_508 = 508, - NotExtended_510 = 510, - NetworkAuthenticationRequired_511 = 511, -}; +typedef std::function ContentProducer; +typedef std::function ContentReceiver; +typedef std::function Progress; -using Headers = std::multimap; - -using Params = std::multimap; -using Match = std::smatch; - -using Progress = std::function; - -struct Response; -using ResponseHandler = std::function; - -struct MultipartFormData { - std::string name; - std::string content; +struct MultipartFile { std::string filename; std::string content_type; + size_t offset = 0; + size_t length = 0; }; -using MultipartFormDataItems = std::vector; -using MultipartFormDataMap = std::multimap; - -class DataSink { -public: - DataSink() : os(&sb_), sb_(*this) {} - - DataSink(const DataSink &) = delete; - DataSink &operator=(const DataSink &) = delete; - DataSink(DataSink &&) = delete; - DataSink &operator=(DataSink &&) = delete; - - std::function write; - std::function is_writable; - std::function done; - std::function done_with_trailer; - std::ostream os; - -private: - class data_sink_streambuf : public std::streambuf { - public: - explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {} - - protected: - std::streamsize xsputn(const char *s, std::streamsize n) override { - sink_.write(s, static_cast(n)); - return n; - } - - private: - DataSink &sink_; - }; - - data_sink_streambuf sb_; -}; - -using ContentProvider = - std::function; - -using ContentProviderWithoutLength = - std::function; - -using ContentProviderResourceReleaser = std::function; - -struct MultipartFormDataProvider { - std::string name; - ContentProviderWithoutLength provider; - std::string filename; - std::string content_type; -}; -using MultipartFormDataProviderItems = std::vector; - -using ContentReceiverWithProgress = - std::function; - -using ContentReceiver = - std::function; - -using MultipartContentHeader = - std::function; - -class ContentReader { -public: - using Reader = std::function; - using MultipartReader = std::function; - - ContentReader(Reader reader, MultipartReader multipart_reader) - : reader_(std::move(reader)), - multipart_reader_(std::move(multipart_reader)) {} - - bool operator()(MultipartContentHeader header, - ContentReceiver receiver) const { - return multipart_reader_(std::move(header), std::move(receiver)); - } - - bool operator()(ContentReceiver receiver) const { - return reader_(std::move(receiver)); - } - - Reader reader_; - MultipartReader multipart_reader_; -}; - -using Range = std::pair; -using Ranges = std::vector; +typedef std::multimap MultipartFiles; struct Request { + std::string version; std::string method; + std::string target; std::string path; Headers headers; std::string body; - - std::string remote_addr; - int remote_port = -1; - std::string local_addr; - int local_port = -1; - - // for server - std::string version; - std::string target; Params params; - MultipartFormDataMap files; - Ranges ranges; + MultipartFiles files; Match matches; - std::unordered_map path_params; - // for client - ResponseHandler response_handler; - ContentReceiverWithProgress content_receiver; - Progress progress; #ifdef CPPHTTPLIB_OPENSSL_SUPPORT - const SSL *ssl = nullptr; + const SSL *ssl; #endif - bool has_header(const std::string &key) const; - std::string get_header_value(const std::string &key, size_t id = 0) const; - uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const; - size_t get_header_value_count(const std::string &key) const; - void set_header(const std::string &key, const std::string &val); + bool has_header(const char *key) const; + std::string get_header_value(const char *key, size_t id = 0) const; + size_t get_header_value_count(const char *key) const; + void set_header(const char *key, const char *val); - bool has_param(const std::string &key) const; - std::string get_param_value(const std::string &key, size_t id = 0) const; - size_t get_param_value_count(const std::string &key) const; + bool has_param(const char *key) const; + std::string get_param_value(const char *key, size_t id = 0) const; + size_t get_param_value_count(const char *key) const; - bool is_multipart_form_data() const; - - bool has_file(const std::string &key) const; - MultipartFormData get_file_value(const std::string &key) const; - std::vector get_file_values(const std::string &key) const; - - // private members... - size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT; - size_t content_length_ = 0; - ContentProvider content_provider_; - bool is_chunked_content_provider_ = false; - size_t authorization_count_ = 0; + bool has_file(const char *key) const; + MultipartFile get_file_value(const char *key) const; }; struct Response { std::string version; - int status = -1; - std::string reason; + int status; Headers headers; std::string body; - std::string location; // Redirect location - bool has_header(const std::string &key) const; - std::string get_header_value(const std::string &key, size_t id = 0) const; - uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const; - size_t get_header_value_count(const std::string &key) const; - void set_header(const std::string &key, const std::string &val); + ContentProducer content_producer; + ContentReceiver content_receiver; + Progress progress; - void set_redirect(const std::string &url, int status = StatusCode::Found_302); - void set_content(const char *s, size_t n, const std::string &content_type); - void set_content(const std::string &s, const std::string &content_type); - void set_content(std::string &&s, const std::string &content_type); + bool has_header(const char *key) const; + std::string get_header_value(const char *key, size_t id = 0) const; + size_t get_header_value_count(const char *key) const; + void set_header(const char *key, const char *val); - void set_content_provider( - size_t length, const std::string &content_type, ContentProvider provider, - ContentProviderResourceReleaser resource_releaser = nullptr); + void set_redirect(const char *uri); + void set_content(const char *s, size_t n, const char *content_type); + void set_content(const std::string &s, const char *content_type); - void set_content_provider( - const std::string &content_type, ContentProviderWithoutLength provider, - ContentProviderResourceReleaser resource_releaser = nullptr); - - void set_chunked_content_provider( - const std::string &content_type, ContentProviderWithoutLength provider, - ContentProviderResourceReleaser resource_releaser = nullptr); - - Response() = default; - Response(const Response &) = default; - Response &operator=(const Response &) = default; - Response(Response &&) = default; - Response &operator=(Response &&) = default; - ~Response() { - if (content_provider_resource_releaser_) { - content_provider_resource_releaser_(content_provider_success_); - } - } - - // private members... - size_t content_length_ = 0; - ContentProvider content_provider_; - ContentProviderResourceReleaser content_provider_resource_releaser_; - bool is_chunked_content_provider_ = false; - bool content_provider_success_ = false; + Response() : status(-1) {} }; class Stream { public: - virtual ~Stream() = default; - - virtual bool is_readable() const = 0; - virtual bool is_writable() const = 0; - - virtual ssize_t read(char *ptr, size_t size) = 0; - virtual ssize_t write(const char *ptr, size_t size) = 0; - virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0; - virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0; - virtual socket_t socket() const = 0; + virtual ~Stream() {} + virtual int read(char *ptr, size_t size) = 0; + virtual int write(const char *ptr, size_t size1) = 0; + virtual int write(const char *ptr) = 0; + virtual std::string get_remote_addr() const = 0; template - ssize_t write_format(const char *fmt, const Args &...args); - ssize_t write(const char *ptr); - ssize_t write(const std::string &s); + void write_format(const char *fmt, const Args &... args); }; -class TaskQueue { +class SocketStream : public Stream { public: - TaskQueue() = default; - virtual ~TaskQueue() = default; + SocketStream(socket_t sock); + virtual ~SocketStream(); - virtual bool enqueue(std::function fn) = 0; - virtual void shutdown() = 0; - - virtual void on_idle() {} -}; - -class ThreadPool : public TaskQueue { -public: - explicit ThreadPool(size_t n, size_t mqr = 0) - : shutdown_(false), max_queued_requests_(mqr) { - while (n) { - threads_.emplace_back(worker(*this)); - n--; - } - } - - ThreadPool(const ThreadPool &) = delete; - ~ThreadPool() override = default; - - bool enqueue(std::function fn) override { - { - std::unique_lock lock(mutex_); - if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) { - return false; - } - jobs_.push_back(std::move(fn)); - } - - cond_.notify_one(); - return true; - } - - void shutdown() override { - // Stop all worker threads... - { - std::unique_lock lock(mutex_); - shutdown_ = true; - } - - cond_.notify_all(); - - // Join... - for (auto &t : threads_) { - t.join(); - } - } + virtual int read(char *ptr, size_t size); + virtual int write(const char *ptr, size_t size); + virtual int write(const char *ptr); + virtual std::string get_remote_addr() const; private: - struct worker { - explicit worker(ThreadPool &pool) : pool_(pool) {} - - void operator()() { - for (;;) { - std::function fn; - { - std::unique_lock lock(pool_.mutex_); - - pool_.cond_.wait( - lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; }); - - if (pool_.shutdown_ && pool_.jobs_.empty()) { break; } - - fn = std::move(pool_.jobs_.front()); - pool_.jobs_.pop_front(); - } - - assert(true == static_cast(fn)); - fn(); - } - } - - ThreadPool &pool_; - }; - friend struct worker; - - std::vector threads_; - std::list> jobs_; - - bool shutdown_; - size_t max_queued_requests_ = 0; - - std::condition_variable cond_; - std::mutex mutex_; + socket_t sock_; }; -using Logger = std::function; - -using SocketOptions = std::function; - -void default_socket_options(socket_t sock); - -const char *status_message(int status); - -std::string get_bearer_token_auth(const Request &req); - -namespace detail { - -class MatcherBase { +class BufferStream : public Stream { public: - virtual ~MatcherBase() = default; + BufferStream() {} + virtual ~BufferStream() {} - // Match request path and populate its matches and - virtual bool match(Request &request) const = 0; -}; + virtual int read(char *ptr, size_t size); + virtual int write(const char *ptr, size_t size); + virtual int write(const char *ptr); + virtual std::string get_remote_addr() const; -/** - * Captures parameters in request path and stores them in Request::path_params - * - * Capture name is a substring of a pattern from : to /. - * The rest of the pattern is matched agains the request path directly - * Parameters are captured starting from the next character after - * the end of the last matched static pattern fragment until the next /. - * - * Example pattern: - * "/path/fragments/:capture/more/fragments/:second_capture" - * Static fragments: - * "/path/fragments/", "more/fragments/" - * - * Given the following request path: - * "/path/fragments/:1/more/fragments/:2" - * the resulting capture will be - * {{"capture", "1"}, {"second_capture", "2"}} - */ -class PathParamsMatcher : public MatcherBase { -public: - PathParamsMatcher(const std::string &pattern); - - bool match(Request &request) const override; + const std::string &get_buffer() const; private: - static constexpr char marker = ':'; - // Treat segment separators as the end of path parameter capture - // Does not need to handle query parameters as they are parsed before path - // matching - static constexpr char separator = '/'; - - // Contains static path fragments to match against, excluding the '/' after - // path params - // Fragments are separated by path params - std::vector static_fragments_; - // Stores the names of the path parameters to be used as keys in the - // Request::path_params map - std::vector param_names_; + std::string buffer; }; -/** - * Performs std::regex_match on request path - * and stores the result in Request::matches - * - * Note that regex match is performed directly on the whole request. - * This means that wildcard patterns may match multiple path segments with /: - * "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end". - */ -class RegexMatcher : public MatcherBase { -public: - RegexMatcher(const std::string &pattern) : regex_(pattern) {} - - bool match(Request &request) const override; - -private: - std::regex regex_; -}; - -ssize_t write_headers(Stream &strm, const Headers &headers); - -} // namespace detail - class Server { public: - using Handler = std::function; - - using ExceptionHandler = - std::function; - - enum class HandlerResponse { - Handled, - Unhandled, - }; - using HandlerWithResponse = - std::function; - - using HandlerWithContentReader = std::function; - - using Expect100ContinueHandler = - std::function; + typedef std::function Handler; + typedef std::function Logger; Server(); @@ -850,931 +240,201 @@ public: virtual bool is_valid() const; - Server &Get(const std::string &pattern, Handler handler); - Server &Post(const std::string &pattern, Handler handler); - Server &Post(const std::string &pattern, HandlerWithContentReader handler); - Server &Put(const std::string &pattern, Handler handler); - Server &Put(const std::string &pattern, HandlerWithContentReader handler); - Server &Patch(const std::string &pattern, Handler handler); - Server &Patch(const std::string &pattern, HandlerWithContentReader handler); - Server &Delete(const std::string &pattern, Handler handler); - Server &Delete(const std::string &pattern, HandlerWithContentReader handler); - Server &Options(const std::string &pattern, Handler handler); + Server &Get(const char *pattern, Handler handler); + Server &Post(const char *pattern, Handler handler); - bool set_base_dir(const std::string &dir, - const std::string &mount_point = std::string()); - bool set_mount_point(const std::string &mount_point, const std::string &dir, - Headers headers = Headers()); - bool remove_mount_point(const std::string &mount_point); - Server &set_file_extension_and_mimetype_mapping(const std::string &ext, - const std::string &mime); - Server &set_default_file_mimetype(const std::string &mime); - Server &set_file_request_handler(Handler handler); + Server &Put(const char *pattern, Handler handler); + Server &Patch(const char *pattern, Handler handler); + Server &Delete(const char *pattern, Handler handler); + Server &Options(const char *pattern, Handler handler); - Server &set_error_handler(HandlerWithResponse handler); - Server &set_error_handler(Handler handler); - Server &set_exception_handler(ExceptionHandler handler); - Server &set_pre_routing_handler(HandlerWithResponse handler); - Server &set_post_routing_handler(Handler handler); - - Server &set_expect_100_continue_handler(Expect100ContinueHandler handler); - Server &set_logger(Logger logger); - - Server &set_address_family(int family); - Server &set_tcp_nodelay(bool on); - Server &set_socket_options(SocketOptions socket_options); - - Server &set_default_headers(Headers headers); - Server & - set_header_writer(std::function const &writer); - - Server &set_keep_alive_max_count(size_t count); - Server &set_keep_alive_timeout(time_t sec); - - Server &set_read_timeout(time_t sec, time_t usec = 0); - template - Server &set_read_timeout(const std::chrono::duration &duration); - - Server &set_write_timeout(time_t sec, time_t usec = 0); - template - Server &set_write_timeout(const std::chrono::duration &duration); - - Server &set_idle_interval(time_t sec, time_t usec = 0); - template - Server &set_idle_interval(const std::chrono::duration &duration); - - Server &set_payload_max_length(size_t length); - - bool bind_to_port(const std::string &host, int port, int socket_flags = 0); - int bind_to_any_port(const std::string &host, int socket_flags = 0); - bool listen_after_bind(); - - bool listen(const std::string &host, int port, int socket_flags = 0); - - bool is_running() const; - void wait_until_ready() const; - void stop(); - - std::function new_task_queue; - -protected: - bool process_request(Stream &strm, bool close_connection, - bool &connection_closed, - const std::function &setup_request); - - std::atomic svr_sock_{INVALID_SOCKET}; - size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT; - time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND; - time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND; - time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND; - time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND; - time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND; - time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND; - time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND; - size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH; - -private: - using Handlers = - std::vector, Handler>>; - using HandlersForContentReader = - std::vector, - HandlerWithContentReader>>; - - static std::unique_ptr - make_matcher(const std::string &pattern); - - socket_t create_server_socket(const std::string &host, int port, - int socket_flags, - SocketOptions socket_options) const; - int bind_internal(const std::string &host, int port, int socket_flags); - bool listen_internal(); - - bool routing(Request &req, Response &res, Stream &strm); - bool handle_file_request(const Request &req, Response &res, - bool head = false); - bool dispatch_request(Request &req, Response &res, - const Handlers &handlers) const; - bool dispatch_request_for_content_reader( - Request &req, Response &res, ContentReader content_reader, - const HandlersForContentReader &handlers) const; - - bool parse_request_line(const char *s, Request &req) const; - void apply_ranges(const Request &req, Response &res, - std::string &content_type, std::string &boundary) const; - bool write_response(Stream &strm, bool close_connection, Request &req, - Response &res); - bool write_response_with_content(Stream &strm, bool close_connection, - const Request &req, Response &res); - bool write_response_core(Stream &strm, bool close_connection, - const Request &req, Response &res, - bool need_apply_ranges); - bool write_content_with_provider(Stream &strm, const Request &req, - Response &res, const std::string &boundary, - const std::string &content_type); - bool read_content(Stream &strm, Request &req, Response &res); - bool - read_content_with_content_receiver(Stream &strm, Request &req, Response &res, - ContentReceiver receiver, - MultipartContentHeader multipart_header, - ContentReceiver multipart_receiver); - bool read_content_core(Stream &strm, Request &req, Response &res, - ContentReceiver receiver, - MultipartContentHeader multipart_header, - ContentReceiver multipart_receiver) const; - - virtual bool process_and_close_socket(socket_t sock); - - std::atomic is_running_{false}; - std::atomic done_{false}; - - struct MountPointEntry { - std::string mount_point; - std::string base_dir; - Headers headers; - }; - std::vector base_dirs_; - std::map file_extension_and_mimetype_map_; - std::string default_file_mimetype_ = "application/octet-stream"; - Handler file_request_handler_; - - Handlers get_handlers_; - Handlers post_handlers_; - HandlersForContentReader post_handlers_for_content_reader_; - Handlers put_handlers_; - HandlersForContentReader put_handlers_for_content_reader_; - Handlers patch_handlers_; - HandlersForContentReader patch_handlers_for_content_reader_; - Handlers delete_handlers_; - HandlersForContentReader delete_handlers_for_content_reader_; - Handlers options_handlers_; - - HandlerWithResponse error_handler_; - ExceptionHandler exception_handler_; - HandlerWithResponse pre_routing_handler_; - Handler post_routing_handler_; - Expect100ContinueHandler expect_100_continue_handler_; - - Logger logger_; - - int address_family_ = AF_UNSPEC; - bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY; - SocketOptions socket_options_ = default_socket_options; - - Headers default_headers_; - std::function header_writer_ = - detail::write_headers; -}; - -enum class Error { - Success = 0, - Unknown, - Connection, - BindIPAddress, - Read, - Write, - ExceedRedirectCount, - Canceled, - SSLConnection, - SSLLoadingCerts, - SSLServerVerification, - UnsupportedMultipartBoundaryChars, - Compression, - ConnectionTimeout, - ProxyConnection, - - // For internal use only - SSLPeerCouldBeClosed_, -}; - -std::string to_string(Error error); - -std::ostream &operator<<(std::ostream &os, const Error &obj); - -class Result { -public: - Result() = default; - Result(std::unique_ptr &&res, Error err, - Headers &&request_headers = Headers{}) - : res_(std::move(res)), err_(err), - request_headers_(std::move(request_headers)) {} - // Response - operator bool() const { return res_ != nullptr; } - bool operator==(std::nullptr_t) const { return res_ == nullptr; } - bool operator!=(std::nullptr_t) const { return res_ != nullptr; } - const Response &value() const { return *res_; } - Response &value() { return *res_; } - const Response &operator*() const { return *res_; } - Response &operator*() { return *res_; } - const Response *operator->() const { return res_.get(); } - Response *operator->() { return res_.get(); } - - // Error - Error error() const { return err_; } - - // Request Headers - bool has_request_header(const std::string &key) const; - std::string get_request_header_value(const std::string &key, - size_t id = 0) const; - uint64_t get_request_header_value_u64(const std::string &key, - size_t id = 0) const; - size_t get_request_header_value_count(const std::string &key) const; - -private: - std::unique_ptr res_; - Error err_ = Error::Unknown; - Headers request_headers_; -}; - -class ClientImpl { -public: - explicit ClientImpl(const std::string &host); - - explicit ClientImpl(const std::string &host, int port); - - explicit ClientImpl(const std::string &host, int port, - const std::string &client_cert_path, - const std::string &client_key_path); - - virtual ~ClientImpl(); - - virtual bool is_valid() const; - - Result Get(const std::string &path); - Result Get(const std::string &path, const Headers &headers); - Result Get(const std::string &path, Progress progress); - Result Get(const std::string &path, const Headers &headers, - Progress progress); - Result Get(const std::string &path, ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver); - Result Get(const std::string &path, ContentReceiver content_receiver, - Progress progress); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, Progress progress); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress); - - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ContentReceiver content_receiver, - Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress = nullptr); - - Result Head(const std::string &path); - Result Head(const std::string &path, const Headers &headers); - - Result Post(const std::string &path); - Result Post(const std::string &path, const Headers &headers); - Result Post(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Post(const std::string &path, const std::string &body, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Post(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Params ¶ms); - Result Post(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Post(const std::string &path, const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); - - Result Put(const std::string &path); - Result Put(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Put(const std::string &path, const std::string &body, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Put(const std::string &path, size_t content_length, - ContentProvider content_provider, const std::string &content_type); - Result Put(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Params ¶ms); - Result Put(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Put(const std::string &path, const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); - - Result Patch(const std::string &path); - Result Patch(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const std::string &body, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - - Result Delete(const std::string &path); - Result Delete(const std::string &path, const Headers &headers); - Result Delete(const std::string &path, const char *body, - size_t content_length, const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Delete(const std::string &path, const std::string &body, - const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - - Result Options(const std::string &path); - Result Options(const std::string &path, const Headers &headers); - - bool send(Request &req, Response &res, Error &error); - Result send(const Request &req); - - void stop(); - - std::string host() const; - int port() const; - - size_t is_socket_open() const; - socket_t socket() const; - - void set_hostname_addr_map(std::map addr_map); - - void set_default_headers(Headers headers); - - void - set_header_writer(std::function const &writer); - - void set_address_family(int family); - void set_tcp_nodelay(bool on); - void set_socket_options(SocketOptions socket_options); - - void set_connection_timeout(time_t sec, time_t usec = 0); - template - void - set_connection_timeout(const std::chrono::duration &duration); - - void set_read_timeout(time_t sec, time_t usec = 0); - template - void set_read_timeout(const std::chrono::duration &duration); - - void set_write_timeout(time_t sec, time_t usec = 0); - template - void set_write_timeout(const std::chrono::duration &duration); - - void set_basic_auth(const std::string &username, const std::string &password); - void set_bearer_token_auth(const std::string &token); -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void set_digest_auth(const std::string &username, - const std::string &password); -#endif - - void set_keep_alive(bool on); - void set_follow_location(bool on); - - void set_url_encode(bool on); - - void set_compress(bool on); - - void set_decompress(bool on); - - void set_interface(const std::string &intf); - - void set_proxy(const std::string &host, int port); - void set_proxy_basic_auth(const std::string &username, - const std::string &password); - void set_proxy_bearer_token_auth(const std::string &token); -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void set_proxy_digest_auth(const std::string &username, - const std::string &password); -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void set_ca_cert_path(const std::string &ca_cert_file_path, - const std::string &ca_cert_dir_path = std::string()); - void set_ca_cert_store(X509_STORE *ca_cert_store); - X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const; -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void enable_server_certificate_verification(bool enabled); -#endif + bool set_base_dir(const char *path); + void set_error_handler(Handler handler); void set_logger(Logger logger); + void set_keep_alive_max_count(size_t count); + void set_payload_max_length(uint64_t length); + + int bind_to_any_port(const char *host, int socket_flags = 0); + bool listen_after_bind(); + + bool listen(const char *host, int port, int socket_flags = 0); + + bool is_running() const; + void stop(); + protected: - struct Socket { - socket_t sock = INVALID_SOCKET; -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - SSL *ssl = nullptr; -#endif + bool process_request(Stream &strm, bool last_connection, + bool &connection_close, + std::function setup_request = nullptr); - bool is_open() const { return sock != INVALID_SOCKET; } - }; - - virtual bool create_and_connect_socket(Socket &socket, Error &error); - - // All of: - // shutdown_ssl - // shutdown_socket - // close_socket - // should ONLY be called when socket_mutex_ is locked. - // Also, shutdown_ssl and close_socket should also NOT be called concurrently - // with a DIFFERENT thread sending requests using that socket. - virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully); - void shutdown_socket(Socket &socket) const; - void close_socket(Socket &socket); - - bool process_request(Stream &strm, Request &req, Response &res, - bool close_connection, Error &error); - - bool write_content_with_provider(Stream &strm, const Request &req, - Error &error) const; - - void copy_settings(const ClientImpl &rhs); - - // Socket endpoint information - const std::string host_; - const int port_; - const std::string host_and_port_; - - // Current open socket - Socket socket_; - mutable std::mutex socket_mutex_; - std::recursive_mutex request_mutex_; - - // These are all protected under socket_mutex - size_t socket_requests_in_flight_ = 0; - std::thread::id socket_requests_are_from_thread_ = std::thread::id(); - bool socket_should_be_closed_when_request_is_done_ = false; - - // Hostname-IP map - std::map addr_map_; - - // Default headers - Headers default_headers_; - - // Header writer - std::function header_writer_ = - detail::write_headers; - - // Settings - std::string client_cert_path_; - std::string client_key_path_; - - time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND; - time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND; - time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND; - time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND; - time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND; - time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND; - - std::string basic_auth_username_; - std::string basic_auth_password_; - std::string bearer_token_auth_token_; -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - std::string digest_auth_username_; - std::string digest_auth_password_; -#endif - - bool keep_alive_ = false; - bool follow_location_ = false; - - bool url_encode_ = true; - - int address_family_ = AF_UNSPEC; - bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY; - SocketOptions socket_options_ = nullptr; - - bool compress_ = false; - bool decompress_ = true; - - std::string interface_; - - std::string proxy_host_; - int proxy_port_ = -1; - - std::string proxy_basic_auth_username_; - std::string proxy_basic_auth_password_; - std::string proxy_bearer_token_auth_token_; -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - std::string proxy_digest_auth_username_; - std::string proxy_digest_auth_password_; -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - std::string ca_cert_file_path_; - std::string ca_cert_dir_path_; - - X509_STORE *ca_cert_store_ = nullptr; -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - bool server_certificate_verification_ = true; -#endif - - Logger logger_; + size_t keep_alive_max_count_; + size_t payload_max_length_; private: - bool send_(Request &req, Response &res, Error &error); - Result send_(Request &&req); + typedef std::vector> Handlers; - socket_t create_client_socket(Error &error) const; - bool read_response_line(Stream &strm, const Request &req, - Response &res) const; - bool write_request(Stream &strm, Request &req, bool close_connection, - Error &error); - bool redirect(Request &req, Response &res, Error &error); - bool handle_request(Stream &strm, Request &req, Response &res, - bool close_connection, Error &error); - std::unique_ptr send_with_content_provider( - Request &req, const char *body, size_t content_length, - ContentProvider content_provider, - ContentProviderWithoutLength content_provider_without_length, - const std::string &content_type, Error &error); - Result send_with_content_provider( - const std::string &method, const std::string &path, - const Headers &headers, const char *body, size_t content_length, - ContentProvider content_provider, - ContentProviderWithoutLength content_provider_without_length, - const std::string &content_type); - ContentProviderWithoutLength get_multipart_content_provider( - const std::string &boundary, const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) const; + socket_t create_server_socket(const char *host, int port, + int socket_flags) const; + int bind_internal(const char *host, int port, int socket_flags); + bool listen_internal(); - std::string adjust_host_string(const std::string &host) const; + bool routing(Request &req, Response &res); + bool handle_file_request(Request &req, Response &res); + bool dispatch_request(Request &req, Response &res, Handlers &handlers); - virtual bool process_socket(const Socket &socket, - std::function callback); - virtual bool is_ssl() const; + bool parse_request_line(const char *s, Request &req); + void write_response(Stream &strm, bool last_connection, const Request &req, + Response &res); + + virtual bool read_and_close_socket(socket_t sock); + + std::atomic is_running_; + std::atomic svr_sock_; + std::string base_dir_; + Handlers get_handlers_; + Handlers post_handlers_; + Handlers put_handlers_; + Handlers patch_handlers_; + Handlers delete_handlers_; + Handlers options_handlers_; + Handler error_handler_; + Logger logger_; + + // TODO: Use thread pool... + std::mutex running_threads_mutex_; + int running_threads_; }; class Client { public: - // Universal interface - explicit Client(const std::string &scheme_host_port); + Client(const char *host, int port = 80, time_t timeout_sec = 300); - explicit Client(const std::string &scheme_host_port, - const std::string &client_cert_path, - const std::string &client_key_path); + virtual ~Client(); - // HTTP only interface - explicit Client(const std::string &host, int port); + virtual bool is_valid() const; - explicit Client(const std::string &host, int port, - const std::string &client_cert_path, - const std::string &client_key_path); + std::shared_ptr Get(const char *path, Progress progress = nullptr); + std::shared_ptr Get(const char *path, const Headers &headers, + Progress progress = nullptr); - Client(Client &&) = default; + std::shared_ptr Get(const char *path, + ContentReceiver content_receiver, + Progress progress = nullptr); + std::shared_ptr Get(const char *path, const Headers &headers, + ContentReceiver content_receiver, + Progress progress = nullptr); - ~Client(); + std::shared_ptr Head(const char *path); + std::shared_ptr Head(const char *path, const Headers &headers); - bool is_valid() const; + std::shared_ptr Post(const char *path, const std::string &body, + const char *content_type); + std::shared_ptr Post(const char *path, const Headers &headers, + const std::string &body, + const char *content_type); - Result Get(const std::string &path); - Result Get(const std::string &path, const Headers &headers); - Result Get(const std::string &path, Progress progress); - Result Get(const std::string &path, const Headers &headers, - Progress progress); - Result Get(const std::string &path, ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver); - Result Get(const std::string &path, ContentReceiver content_receiver, - Progress progress); - Result Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, Progress progress); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver); - Result Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, ContentReceiver content_receiver, - Progress progress); - Result Get(const std::string &path, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress); + std::shared_ptr Post(const char *path, const Params ¶ms); + std::shared_ptr Post(const char *path, const Headers &headers, + const Params ¶ms); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ContentReceiver content_receiver, - Progress progress = nullptr); - Result Get(const std::string &path, const Params ¶ms, - const Headers &headers, ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress = nullptr); + std::shared_ptr Put(const char *path, const std::string &body, + const char *content_type); + std::shared_ptr Put(const char *path, const Headers &headers, + const std::string &body, + const char *content_type); - Result Head(const std::string &path); - Result Head(const std::string &path, const Headers &headers); + std::shared_ptr Patch(const char *path, const std::string &body, + const char *content_type); + std::shared_ptr Patch(const char *path, const Headers &headers, + const std::string &body, + const char *content_type); - Result Post(const std::string &path); - Result Post(const std::string &path, const Headers &headers); - Result Post(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Post(const std::string &path, const std::string &body, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Post(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Post(const std::string &path, const Params ¶ms); - Result Post(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Post(const std::string &path, const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); + std::shared_ptr Delete(const char *path, + const std::string &body = std::string(), + const char *content_type = nullptr); + std::shared_ptr Delete(const char *path, const Headers &headers, + const std::string &body = std::string(), + const char *content_type = nullptr); - Result Put(const std::string &path); - Result Put(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, const char *body, - size_t content_length, const std::string &content_type); - Result Put(const std::string &path, const std::string &body, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Put(const std::string &path, size_t content_length, - ContentProvider content_provider, const std::string &content_type); - Result Put(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Put(const std::string &path, const Params ¶ms); - Result Put(const std::string &path, const Headers &headers, - const Params ¶ms); - Result Put(const std::string &path, const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, const std::string &boundary); - Result Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items); + std::shared_ptr Options(const char *path); + std::shared_ptr Options(const char *path, const Headers &headers); - Result Patch(const std::string &path); - Result Patch(const std::string &path, const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Patch(const std::string &path, const std::string &body, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); - Result Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - size_t content_length, ContentProvider content_provider, - const std::string &content_type); - Result Patch(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type); + bool send(Request &req, Response &res); - Result Delete(const std::string &path); - Result Delete(const std::string &path, const Headers &headers); - Result Delete(const std::string &path, const char *body, - size_t content_length, const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type); - Result Delete(const std::string &path, const std::string &body, - const std::string &content_type); - Result Delete(const std::string &path, const Headers &headers, - const std::string &body, const std::string &content_type); +protected: + bool process_request(Stream &strm, Request &req, Response &res, + bool &connection_close); - Result Options(const std::string &path); - Result Options(const std::string &path, const Headers &headers); - - bool send(Request &req, Response &res, Error &error); - Result send(const Request &req); - - void stop(); - - std::string host() const; - int port() const; - - size_t is_socket_open() const; - socket_t socket() const; - - void set_hostname_addr_map(std::map addr_map); - - void set_default_headers(Headers headers); - - void - set_header_writer(std::function const &writer); - - void set_address_family(int family); - void set_tcp_nodelay(bool on); - void set_socket_options(SocketOptions socket_options); - - void set_connection_timeout(time_t sec, time_t usec = 0); - template - void - set_connection_timeout(const std::chrono::duration &duration); - - void set_read_timeout(time_t sec, time_t usec = 0); - template - void set_read_timeout(const std::chrono::duration &duration); - - void set_write_timeout(time_t sec, time_t usec = 0); - template - void set_write_timeout(const std::chrono::duration &duration); - - void set_basic_auth(const std::string &username, const std::string &password); - void set_bearer_token_auth(const std::string &token); -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void set_digest_auth(const std::string &username, - const std::string &password); -#endif - - void set_keep_alive(bool on); - void set_follow_location(bool on); - - void set_url_encode(bool on); - - void set_compress(bool on); - - void set_decompress(bool on); - - void set_interface(const std::string &intf); - - void set_proxy(const std::string &host, int port); - void set_proxy_basic_auth(const std::string &username, - const std::string &password); - void set_proxy_bearer_token_auth(const std::string &token); -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void set_proxy_digest_auth(const std::string &username, - const std::string &password); -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void enable_server_certificate_verification(bool enabled); -#endif - - void set_logger(Logger logger); - - // SSL -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - void set_ca_cert_path(const std::string &ca_cert_file_path, - const std::string &ca_cert_dir_path = std::string()); - - void set_ca_cert_store(X509_STORE *ca_cert_store); - void load_ca_cert_store(const char *ca_cert, std::size_t size); - - long get_openssl_verify_result() const; - - SSL_CTX *ssl_context() const; -#endif + const std::string host_; + const int port_; + time_t timeout_sec_; + const std::string host_and_port_; private: - std::unique_ptr cli_; + socket_t create_client_socket() const; + bool read_response_line(Stream &strm, Response &res); + void write_request(Stream &strm, Request &req); -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - bool is_ssl_ = false; -#endif + virtual bool read_and_close_socket(socket_t sock, Request &req, + Response &res); + virtual bool is_ssl() const; }; #ifdef CPPHTTPLIB_OPENSSL_SUPPORT +class SSLSocketStream : public Stream { +public: + SSLSocketStream(socket_t sock, SSL *ssl); + virtual ~SSLSocketStream(); + + virtual int read(char *ptr, size_t size); + virtual int write(const char *ptr, size_t size); + virtual int write(const char *ptr); + virtual std::string get_remote_addr() const; + +private: + socket_t sock_; + SSL *ssl_; +}; + class SSLServer : public Server { public: SSLServer(const char *cert_path, const char *private_key_path, const char *client_ca_cert_file_path = nullptr, - const char *client_ca_cert_dir_path = nullptr, - const char *private_key_password = nullptr); + const char *client_ca_cert_dir_path = nullptr); - SSLServer(X509 *cert, EVP_PKEY *private_key, - X509_STORE *client_ca_cert_store = nullptr); + virtual ~SSLServer(); - SSLServer( - const std::function &setup_ssl_ctx_callback); - - ~SSLServer() override; - - bool is_valid() const override; - - SSL_CTX *ssl_context() const; + virtual bool is_valid() const; private: - bool process_and_close_socket(socket_t sock) override; + virtual bool read_and_close_socket(socket_t sock); SSL_CTX *ctx_; std::mutex ctx_mutex_; }; -class SSLClient : public ClientImpl { +class SSLClient : public Client { public: - explicit SSLClient(const std::string &host); + SSLClient(const char *host, int port = 443, time_t timeout_sec = 300, + const char *client_cert_path = nullptr, + const char *client_key_path = nullptr); - explicit SSLClient(const std::string &host, int port); + virtual ~SSLClient(); - explicit SSLClient(const std::string &host, int port, - const std::string &client_cert_path, - const std::string &client_key_path); + virtual bool is_valid() const; - explicit SSLClient(const std::string &host, int port, X509 *client_cert, - EVP_PKEY *client_key); - - ~SSLClient() override; - - bool is_valid() const override; - - void set_ca_cert_store(X509_STORE *ca_cert_store); - void load_ca_cert_store(const char *ca_cert, std::size_t size); + void set_ca_cert_path(const char *ca_ceert_file_path, + const char *ca_cert_dir_path = nullptr); + void enable_server_certificate_verification(bool enabled); long get_openssl_verify_result() const; - SSL_CTX *ssl_context() const; - private: - bool create_and_connect_socket(Socket &socket, Error &error) override; - void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override; - void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully); - - bool process_socket(const Socket &socket, - std::function callback) override; - bool is_ssl() const override; - - bool connect_with_proxy(Socket &sock, Response &res, bool &success, - Error &error); - bool initialize_ssl(Socket &socket, Error &error); - - bool load_certs(); + virtual bool read_and_close_socket(socket_t sock, Request &req, + Response &res); + virtual bool is_ssl() const; bool verify_host(X509 *server_cert) const; bool verify_host_with_subject_alt_name(X509 *server_cert) const; @@ -1783,508 +443,17 @@ private: SSL_CTX *ctx_; std::mutex ctx_mutex_; - std::once_flag initialize_cert_; - std::vector host_components_; - + std::string ca_cert_file_path_; + std::string ca_cert_dir_path_; + bool server_certificate_verification_ = false; long verify_result_ = 0; - - friend class ClientImpl; }; #endif /* - * Implementation of template methods. + * Implementation */ - -namespace detail { - -template -inline void duration_to_sec_and_usec(const T &duration, U callback) { - auto sec = std::chrono::duration_cast(duration).count(); - auto usec = std::chrono::duration_cast( - duration - std::chrono::seconds(sec)) - .count(); - callback(static_cast(sec), static_cast(usec)); -} - -inline uint64_t get_header_value_u64(const Headers &headers, - const std::string &key, size_t id, - uint64_t def) { - auto rng = headers.equal_range(key); - auto it = rng.first; - std::advance(it, static_cast(id)); - if (it != rng.second) { - return std::strtoull(it->second.data(), nullptr, 10); - } - return def; -} - -} // namespace detail - -inline uint64_t Request::get_header_value_u64(const std::string &key, - size_t id) const { - return detail::get_header_value_u64(headers, key, id, 0); -} - -inline uint64_t Response::get_header_value_u64(const std::string &key, - size_t id) const { - return detail::get_header_value_u64(headers, key, id, 0); -} - -template -inline ssize_t Stream::write_format(const char *fmt, const Args &...args) { - const auto bufsiz = 2048; - std::array buf{}; - - auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...); - if (sn <= 0) { return sn; } - - auto n = static_cast(sn); - - if (n >= buf.size() - 1) { - std::vector glowable_buf(buf.size()); - - while (n >= glowable_buf.size() - 1) { - glowable_buf.resize(glowable_buf.size() * 2); - n = static_cast( - snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...)); - } - return write(&glowable_buf[0], n); - } else { - return write(buf.data(), n); - } -} - -inline void default_socket_options(socket_t sock) { - int yes = 1; -#ifdef _WIN32 - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&yes), sizeof(yes)); - setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, - reinterpret_cast(&yes), sizeof(yes)); -#else -#ifdef SO_REUSEPORT - setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, - reinterpret_cast(&yes), sizeof(yes)); -#else - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&yes), sizeof(yes)); -#endif -#endif -} - -inline const char *status_message(int status) { - switch (status) { - case StatusCode::Continue_100: return "Continue"; - case StatusCode::SwitchingProtocol_101: return "Switching Protocol"; - case StatusCode::Processing_102: return "Processing"; - case StatusCode::EarlyHints_103: return "Early Hints"; - case StatusCode::OK_200: return "OK"; - case StatusCode::Created_201: return "Created"; - case StatusCode::Accepted_202: return "Accepted"; - case StatusCode::NonAuthoritativeInformation_203: - return "Non-Authoritative Information"; - case StatusCode::NoContent_204: return "No Content"; - case StatusCode::ResetContent_205: return "Reset Content"; - case StatusCode::PartialContent_206: return "Partial Content"; - case StatusCode::MultiStatus_207: return "Multi-Status"; - case StatusCode::AlreadyReported_208: return "Already Reported"; - case StatusCode::IMUsed_226: return "IM Used"; - case StatusCode::MultipleChoices_300: return "Multiple Choices"; - case StatusCode::MovedPermanently_301: return "Moved Permanently"; - case StatusCode::Found_302: return "Found"; - case StatusCode::SeeOther_303: return "See Other"; - case StatusCode::NotModified_304: return "Not Modified"; - case StatusCode::UseProxy_305: return "Use Proxy"; - case StatusCode::unused_306: return "unused"; - case StatusCode::TemporaryRedirect_307: return "Temporary Redirect"; - case StatusCode::PermanentRedirect_308: return "Permanent Redirect"; - case StatusCode::BadRequest_400: return "Bad Request"; - case StatusCode::Unauthorized_401: return "Unauthorized"; - case StatusCode::PaymentRequired_402: return "Payment Required"; - case StatusCode::Forbidden_403: return "Forbidden"; - case StatusCode::NotFound_404: return "Not Found"; - case StatusCode::MethodNotAllowed_405: return "Method Not Allowed"; - case StatusCode::NotAcceptable_406: return "Not Acceptable"; - case StatusCode::ProxyAuthenticationRequired_407: - return "Proxy Authentication Required"; - case StatusCode::RequestTimeout_408: return "Request Timeout"; - case StatusCode::Conflict_409: return "Conflict"; - case StatusCode::Gone_410: return "Gone"; - case StatusCode::LengthRequired_411: return "Length Required"; - case StatusCode::PreconditionFailed_412: return "Precondition Failed"; - case StatusCode::PayloadTooLarge_413: return "Payload Too Large"; - case StatusCode::UriTooLong_414: return "URI Too Long"; - case StatusCode::UnsupportedMediaType_415: return "Unsupported Media Type"; - case StatusCode::RangeNotSatisfiable_416: return "Range Not Satisfiable"; - case StatusCode::ExpectationFailed_417: return "Expectation Failed"; - case StatusCode::ImATeapot_418: return "I'm a teapot"; - case StatusCode::MisdirectedRequest_421: return "Misdirected Request"; - case StatusCode::UnprocessableContent_422: return "Unprocessable Content"; - case StatusCode::Locked_423: return "Locked"; - case StatusCode::FailedDependency_424: return "Failed Dependency"; - case StatusCode::TooEarly_425: return "Too Early"; - case StatusCode::UpgradeRequired_426: return "Upgrade Required"; - case StatusCode::PreconditionRequired_428: return "Precondition Required"; - case StatusCode::TooManyRequests_429: return "Too Many Requests"; - case StatusCode::RequestHeaderFieldsTooLarge_431: - return "Request Header Fields Too Large"; - case StatusCode::UnavailableForLegalReasons_451: - return "Unavailable For Legal Reasons"; - case StatusCode::NotImplemented_501: return "Not Implemented"; - case StatusCode::BadGateway_502: return "Bad Gateway"; - case StatusCode::ServiceUnavailable_503: return "Service Unavailable"; - case StatusCode::GatewayTimeout_504: return "Gateway Timeout"; - case StatusCode::HttpVersionNotSupported_505: - return "HTTP Version Not Supported"; - case StatusCode::VariantAlsoNegotiates_506: return "Variant Also Negotiates"; - case StatusCode::InsufficientStorage_507: return "Insufficient Storage"; - case StatusCode::LoopDetected_508: return "Loop Detected"; - case StatusCode::NotExtended_510: return "Not Extended"; - case StatusCode::NetworkAuthenticationRequired_511: - return "Network Authentication Required"; - - default: - case StatusCode::InternalServerError_500: return "Internal Server Error"; - } -} - -inline std::string get_bearer_token_auth(const Request &req) { - if (req.has_header("Authorization")) { - static std::string BearerHeaderPrefix = "Bearer "; - return req.get_header_value("Authorization") - .substr(BearerHeaderPrefix.length()); - } - return ""; -} - -template -inline Server & -Server::set_read_timeout(const std::chrono::duration &duration) { - detail::duration_to_sec_and_usec( - duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); }); - return *this; -} - -template -inline Server & -Server::set_write_timeout(const std::chrono::duration &duration) { - detail::duration_to_sec_and_usec( - duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); }); - return *this; -} - -template -inline Server & -Server::set_idle_interval(const std::chrono::duration &duration) { - detail::duration_to_sec_and_usec( - duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); }); - return *this; -} - -inline std::string to_string(const Error error) { - switch (error) { - case Error::Success: return "Success (no error)"; - case Error::Connection: return "Could not establish connection"; - case Error::BindIPAddress: return "Failed to bind IP address"; - case Error::Read: return "Failed to read connection"; - case Error::Write: return "Failed to write connection"; - case Error::ExceedRedirectCount: return "Maximum redirect count exceeded"; - case Error::Canceled: return "Connection handling canceled"; - case Error::SSLConnection: return "SSL connection failed"; - case Error::SSLLoadingCerts: return "SSL certificate loading failed"; - case Error::SSLServerVerification: return "SSL server verification failed"; - case Error::UnsupportedMultipartBoundaryChars: - return "Unsupported HTTP multipart boundary characters"; - case Error::Compression: return "Compression failed"; - case Error::ConnectionTimeout: return "Connection timed out"; - case Error::ProxyConnection: return "Proxy connection failed"; - case Error::Unknown: return "Unknown"; - default: break; - } - - return "Invalid"; -} - -inline std::ostream &operator<<(std::ostream &os, const Error &obj) { - os << to_string(obj); - os << " (" << static_cast::type>(obj) << ')'; - return os; -} - -inline uint64_t Result::get_request_header_value_u64(const std::string &key, - size_t id) const { - return detail::get_header_value_u64(request_headers_, key, id, 0); -} - -template -inline void ClientImpl::set_connection_timeout( - const std::chrono::duration &duration) { - detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) { - set_connection_timeout(sec, usec); - }); -} - -template -inline void ClientImpl::set_read_timeout( - const std::chrono::duration &duration) { - detail::duration_to_sec_and_usec( - duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); }); -} - -template -inline void ClientImpl::set_write_timeout( - const std::chrono::duration &duration) { - detail::duration_to_sec_and_usec( - duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); }); -} - -template -inline void Client::set_connection_timeout( - const std::chrono::duration &duration) { - cli_->set_connection_timeout(duration); -} - -template -inline void -Client::set_read_timeout(const std::chrono::duration &duration) { - cli_->set_read_timeout(duration); -} - -template -inline void -Client::set_write_timeout(const std::chrono::duration &duration) { - cli_->set_write_timeout(duration); -} - -/* - * Forward declarations and types that will be part of the .h file if split into - * .h + .cc. - */ - -std::string hosted_at(const std::string &hostname); - -void hosted_at(const std::string &hostname, std::vector &addrs); - -std::string append_query_params(const std::string &path, const Params ¶ms); - -std::pair make_range_header(const Ranges &ranges); - -std::pair -make_basic_authentication_header(const std::string &username, - const std::string &password, - bool is_proxy = false); - -namespace detail { - -std::string encode_query_param(const std::string &value); - -std::string decode_url(const std::string &s, bool convert_plus_to_space); - -void read_file(const std::string &path, std::string &out); - -std::string trim_copy(const std::string &s); - -void split(const char *b, const char *e, char d, - std::function fn); - -void split(const char *b, const char *e, char d, size_t m, - std::function fn); - -bool process_client_socket(socket_t sock, time_t read_timeout_sec, - time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec, - std::function callback); - -socket_t create_client_socket( - const std::string &host, const std::string &ip, int port, - int address_family, bool tcp_nodelay, SocketOptions socket_options, - time_t connection_timeout_sec, time_t connection_timeout_usec, - time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec, const std::string &intf, Error &error); - -const char *get_header_value(const Headers &headers, const std::string &key, - size_t id = 0, const char *def = nullptr); - -std::string params_to_query_str(const Params ¶ms); - -void parse_query_text(const std::string &s, Params ¶ms); - -bool parse_multipart_boundary(const std::string &content_type, - std::string &boundary); - -bool parse_range_header(const std::string &s, Ranges &ranges); - -int close_socket(socket_t sock); - -ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags); - -ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags); - -enum class EncodingType { None = 0, Gzip, Brotli }; - -EncodingType encoding_type(const Request &req, const Response &res); - -class BufferStream : public Stream { -public: - BufferStream() = default; - ~BufferStream() override = default; - - bool is_readable() const override; - bool is_writable() const override; - ssize_t read(char *ptr, size_t size) override; - ssize_t write(const char *ptr, size_t size) override; - void get_remote_ip_and_port(std::string &ip, int &port) const override; - void get_local_ip_and_port(std::string &ip, int &port) const override; - socket_t socket() const override; - - const std::string &get_buffer() const; - -private: - std::string buffer; - size_t position = 0; -}; - -class compressor { -public: - virtual ~compressor() = default; - - typedef std::function Callback; - virtual bool compress(const char *data, size_t data_length, bool last, - Callback callback) = 0; -}; - -class decompressor { -public: - virtual ~decompressor() = default; - - virtual bool is_valid() const = 0; - - typedef std::function Callback; - virtual bool decompress(const char *data, size_t data_length, - Callback callback) = 0; -}; - -class nocompressor : public compressor { -public: - ~nocompressor() override = default; - - bool compress(const char *data, size_t data_length, bool /*last*/, - Callback callback) override; -}; - -#ifdef CPPHTTPLIB_ZLIB_SUPPORT -class gzip_compressor : public compressor { -public: - gzip_compressor(); - ~gzip_compressor() override; - - bool compress(const char *data, size_t data_length, bool last, - Callback callback) override; - -private: - bool is_valid_ = false; - z_stream strm_; -}; - -class gzip_decompressor : public decompressor { -public: - gzip_decompressor(); - ~gzip_decompressor() override; - - bool is_valid() const override; - - bool decompress(const char *data, size_t data_length, - Callback callback) override; - -private: - bool is_valid_ = false; - z_stream strm_; -}; -#endif - -#ifdef CPPHTTPLIB_BROTLI_SUPPORT -class brotli_compressor : public compressor { -public: - brotli_compressor(); - ~brotli_compressor(); - - bool compress(const char *data, size_t data_length, bool last, - Callback callback) override; - -private: - BrotliEncoderState *state_ = nullptr; -}; - -class brotli_decompressor : public decompressor { -public: - brotli_decompressor(); - ~brotli_decompressor(); - - bool is_valid() const override; - - bool decompress(const char *data, size_t data_length, - Callback callback) override; - -private: - BrotliDecoderResult decoder_r; - BrotliDecoderState *decoder_s = nullptr; -}; -#endif - -// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer` -// to store data. The call can set memory on stack for performance. -class stream_line_reader { -public: - stream_line_reader(Stream &strm, char *fixed_buffer, - size_t fixed_buffer_size); - const char *ptr() const; - size_t size() const; - bool end_with_crlf() const; - bool getline(); - -private: - void append(char c); - - Stream &strm_; - char *fixed_buffer_; - const size_t fixed_buffer_size_; - size_t fixed_buffer_used_size_ = 0; - std::string glowable_buffer_; -}; - -class mmap { -public: - mmap(const char *path); - ~mmap(); - - bool open(const char *path); - void close(); - - bool is_open() const; - size_t size() const; - const char *data() const; - -private: -#if defined(_WIN32) - HANDLE hFile_; - HANDLE hMapping_; -#else - int fd_; -#endif - size_t size_; - void *addr_; -}; - -} // namespace detail - -// ---------------------------------------------------------------------------- - -/* - * Implementation that will be part of the .cc file if split into .h + .cc. - */ - namespace detail { inline bool is_hex(char c, int &v) { @@ -2308,7 +477,7 @@ inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, val = 0; for (; cnt; i++, cnt--) { if (!s[i]) { return false; } - auto v = 0; + int v = 0; if (is_hex(s[i], v)) { val = val * 16 + v; } else { @@ -2318,8 +487,8 @@ inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, return true; } -inline std::string from_i_to_hex(size_t n) { - static const auto charset = "0123456789abcdef"; +inline std::string from_i_to_hex(uint64_t n) { + const char *charset = "0123456789abcdef"; std::string ret; do { ret = charset[n & 15] + ret; @@ -2330,29 +499,29 @@ inline std::string from_i_to_hex(size_t n) { inline size_t to_utf8(int code, char *buff) { if (code < 0x0080) { - buff[0] = static_cast(code & 0x7F); + buff[0] = (code & 0x7F); return 1; } else if (code < 0x0800) { - buff[0] = static_cast(0xC0 | ((code >> 6) & 0x1F)); - buff[1] = static_cast(0x80 | (code & 0x3F)); + buff[0] = (0xC0 | ((code >> 6) & 0x1F)); + buff[1] = (0x80 | (code & 0x3F)); return 2; } else if (code < 0xD800) { - buff[0] = static_cast(0xE0 | ((code >> 12) & 0xF)); - buff[1] = static_cast(0x80 | ((code >> 6) & 0x3F)); - buff[2] = static_cast(0x80 | (code & 0x3F)); + buff[0] = (0xE0 | ((code >> 12) & 0xF)); + buff[1] = (0x80 | ((code >> 6) & 0x3F)); + buff[2] = (0x80 | (code & 0x3F)); return 3; } else if (code < 0xE000) { // D800 - DFFF is invalid... return 0; } else if (code < 0x10000) { - buff[0] = static_cast(0xE0 | ((code >> 12) & 0xF)); - buff[1] = static_cast(0x80 | ((code >> 6) & 0x3F)); - buff[2] = static_cast(0x80 | (code & 0x3F)); + buff[0] = (0xE0 | ((code >> 12) & 0xF)); + buff[1] = (0x80 | ((code >> 6) & 0x3F)); + buff[2] = (0x80 | (code & 0x3F)); return 3; } else if (code < 0x110000) { - buff[0] = static_cast(0xF0 | ((code >> 18) & 0x7)); - buff[1] = static_cast(0x80 | ((code >> 12) & 0x3F)); - buff[2] = static_cast(0x80 | ((code >> 6) & 0x3F)); - buff[3] = static_cast(0x80 | (code & 0x3F)); + buff[0] = (0xF0 | ((code >> 18) & 0x7)); + buff[1] = (0x80 | ((code >> 12) & 0x3F)); + buff[2] = (0x80 | ((code >> 6) & 0x3F)); + buff[3] = (0x80 | (code & 0x3F)); return 4; } @@ -2369,11 +538,11 @@ inline std::string base64_encode(const std::string &in) { std::string out; out.reserve(in.size()); - auto val = 0; - auto valb = -6; + int val = 0; + int valb = -6; - for (auto c : in) { - val = (val << 8) + static_cast(c); + for (uint8_t c : in) { + val = (val << 8) + c; valb += 8; while (valb >= 0) { out.push_back(lookup[(val >> valb) & 0x3F]); @@ -2381,7 +550,9 @@ inline std::string base64_encode(const std::string &in) { } } - if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); } + if (valb > -6) { + out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); + } while (out.size() % 4) { out.push_back('='); @@ -2391,12 +562,8 @@ inline std::string base64_encode(const std::string &in) { } inline bool is_file(const std::string &path) { -#ifdef _WIN32 - return _access_s(path.c_str(), 0) == 0; -#else struct stat st; return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode); -#endif } inline bool is_dir(const std::string &path) { @@ -2417,11 +584,6 @@ inline bool is_valid_path(const std::string &path) { // Read component auto beg = i; while (i < path.size() && path[i] != '/') { - if (path[i] == '\0') { - return false; - } else if (path[i] == '\\') { - return false; - } i++; } @@ -2446,320 +608,108 @@ inline bool is_valid_path(const std::string &path) { return true; } -inline std::string encode_query_param(const std::string &value) { - std::ostringstream escaped; - escaped.fill('0'); - escaped << std::hex; - - for (auto c : value) { - if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || - c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' || - c == ')') { - escaped << c; - } else { - escaped << std::uppercase; - escaped << '%' << std::setw(2) - << static_cast(static_cast(c)); - escaped << std::nouppercase; - } - } - - return escaped.str(); -} - -inline std::string encode_url(const std::string &s) { - std::string result; - result.reserve(s.size()); - - for (size_t i = 0; s[i]; i++) { - switch (s[i]) { - case ' ': result += "%20"; break; - case '+': result += "%2B"; break; - case '\r': result += "%0D"; break; - case '\n': result += "%0A"; break; - case '\'': result += "%27"; break; - case ',': result += "%2C"; break; - // case ':': result += "%3A"; break; // ok? probably... - case ';': result += "%3B"; break; - default: - auto c = static_cast(s[i]); - if (c >= 0x80) { - result += '%'; - char hex[4]; - auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c); - assert(len == 2); - result.append(hex, static_cast(len)); - } else { - result += s[i]; - } - break; - } - } - - return result; -} - -inline std::string decode_url(const std::string &s, - bool convert_plus_to_space) { - std::string result; - - for (size_t i = 0; i < s.size(); i++) { - if (s[i] == '%' && i + 1 < s.size()) { - if (s[i + 1] == 'u') { - auto val = 0; - if (from_hex_to_i(s, i + 2, 4, val)) { - // 4 digits Unicode codes - char buff[4]; - size_t len = to_utf8(val, buff); - if (len > 0) { result.append(buff, len); } - i += 5; // 'u0000' - } else { - result += s[i]; - } - } else { - auto val = 0; - if (from_hex_to_i(s, i + 1, 2, val)) { - // 2 digits hex codes - result += static_cast(val); - i += 2; // '00' - } else { - result += s[i]; - } - } - } else if (convert_plus_to_space && s[i] == '+') { - result += ' '; - } else { - result += s[i]; - } - } - - return result; -} - inline void read_file(const std::string &path, std::string &out) { std::ifstream fs(path, std::ios_base::binary); fs.seekg(0, std::ios_base::end); auto size = fs.tellg(); fs.seekg(0); out.resize(static_cast(size)); - fs.read(&out[0], static_cast(size)); + fs.read(&out[0], size); } inline std::string file_extension(const std::string &path) { std::smatch m; - static auto re = std::regex("\\.([a-zA-Z0-9]+)$"); - if (std::regex_search(path, m, re)) { return m[1].str(); } + auto pat = std::regex("\\.([a-zA-Z0-9]+)$"); + if (std::regex_search(path, m, pat)) { return m[1].str(); } return std::string(); } -inline bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; } +template void split(const char *b, const char *e, char d, Fn fn) { + int i = 0; + int beg = 0; -inline std::pair trim(const char *b, const char *e, size_t left, - size_t right) { - while (b + left < e && is_space_or_tab(b[left])) { - left++; - } - while (right > 0 && is_space_or_tab(b[right - 1])) { - right--; - } - return std::make_pair(left, right); -} - -inline std::string trim_copy(const std::string &s) { - auto r = trim(s.data(), s.data() + s.size(), 0, s.size()); - return s.substr(r.first, r.second - r.first); -} - -inline std::string trim_double_quotes_copy(const std::string &s) { - if (s.length() >= 2 && s.front() == '"' && s.back() == '"') { - return s.substr(1, s.size() - 2); - } - return s; -} - -inline void split(const char *b, const char *e, char d, - std::function fn) { - return split(b, e, d, (std::numeric_limits::max)(), std::move(fn)); -} - -inline void split(const char *b, const char *e, char d, size_t m, - std::function fn) { - size_t i = 0; - size_t beg = 0; - size_t count = 1; - - while (e ? (b + i < e) : (b[i] != '\0')) { - if (b[i] == d && count < m) { - auto r = trim(b, e, beg, i); - if (r.first < r.second) { fn(&b[r.first], &b[r.second]); } + while (e ? (b + i != e) : (b[i] != '\0')) { + if (b[i] == d) { + fn(&b[beg], &b[i]); beg = i + 1; - count++; } i++; } - if (i) { - auto r = trim(b, e, beg, i); - if (r.first < r.second) { fn(&b[r.first], &b[r.second]); } - } + if (i) { fn(&b[beg], &b[i]); } } -inline stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer, - size_t fixed_buffer_size) - : strm_(strm), fixed_buffer_(fixed_buffer), - fixed_buffer_size_(fixed_buffer_size) {} +// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer` +// to store data. The call can set memory on stack for performance. +class stream_line_reader { +public: + stream_line_reader(Stream &strm, char *fixed_buffer, size_t fixed_buffer_size) + : strm_(strm), fixed_buffer_(fixed_buffer), + fixed_buffer_size_(fixed_buffer_size) {} -inline const char *stream_line_reader::ptr() const { - if (glowable_buffer_.empty()) { - return fixed_buffer_; - } else { - return glowable_buffer_.data(); - } -} - -inline size_t stream_line_reader::size() const { - if (glowable_buffer_.empty()) { - return fixed_buffer_used_size_; - } else { - return glowable_buffer_.size(); - } -} - -inline bool stream_line_reader::end_with_crlf() const { - auto end = ptr() + size(); - return size() >= 2 && end[-2] == '\r' && end[-1] == '\n'; -} - -inline bool stream_line_reader::getline() { - fixed_buffer_used_size_ = 0; - glowable_buffer_.clear(); - - for (size_t i = 0;; i++) { - char byte; - auto n = strm_.read(&byte, 1); - - if (n < 0) { - return false; - } else if (n == 0) { - if (i == 0) { - return false; - } else { - break; - } - } - - append(byte); - - if (byte == '\n') { break; } - } - - return true; -} - -inline void stream_line_reader::append(char c) { - if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) { - fixed_buffer_[fixed_buffer_used_size_++] = c; - fixed_buffer_[fixed_buffer_used_size_] = '\0'; - } else { + const char *ptr() const { if (glowable_buffer_.empty()) { - assert(fixed_buffer_[fixed_buffer_used_size_] == '\0'); - glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); + return fixed_buffer_; + } else { + return glowable_buffer_.data(); } - glowable_buffer_ += c; - } -} - -inline mmap::mmap(const char *path) -#if defined(_WIN32) - : hFile_(NULL), hMapping_(NULL) -#else - : fd_(-1) -#endif - , - size_(0), addr_(nullptr) { - open(path); -} - -inline mmap::~mmap() { close(); } - -inline bool mmap::open(const char *path) { - close(); - -#if defined(_WIN32) - hFile_ = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (hFile_ == INVALID_HANDLE_VALUE) { return false; } - - size_ = ::GetFileSize(hFile_, NULL); - - hMapping_ = ::CreateFileMapping(hFile_, NULL, PAGE_READONLY, 0, 0, NULL); - - if (hMapping_ == NULL) { - close(); - return false; } - addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0); -#else - fd_ = ::open(path, O_RDONLY); - if (fd_ == -1) { return false; } - - struct stat sb; - if (fstat(fd_, &sb) == -1) { - close(); - return false; - } - size_ = static_cast(sb.st_size); - - addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0); -#endif - - if (addr_ == nullptr) { - close(); - return false; + size_t size() const { + if (glowable_buffer_.empty()) { + return fixed_buffer_used_size_; + } else { + return glowable_buffer_.size(); + } } - return true; -} + bool getline() { + fixed_buffer_used_size_ = 0; + glowable_buffer_.clear(); -inline bool mmap::is_open() const { return addr_ != nullptr; } + for (size_t i = 0;; i++) { + char byte; + auto n = strm_.read(&byte, 1); -inline size_t mmap::size() const { return size_; } + if (n < 0) { + return false; + } else if (n == 0) { + if (i == 0) { + return false; + } else { + break; + } + } -inline const char *mmap::data() const { - return static_cast(addr_); -} + append(byte); -inline void mmap::close() { -#if defined(_WIN32) - if (addr_) { - ::UnmapViewOfFile(addr_); - addr_ = nullptr; + if (byte == '\n') { break; } + } + + return true; } - if (hMapping_) { - ::CloseHandle(hMapping_); - hMapping_ = NULL; +private: + void append(char c) { + if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) { + fixed_buffer_[fixed_buffer_used_size_++] = c; + fixed_buffer_[fixed_buffer_used_size_] = '\0'; + } else { + if (glowable_buffer_.empty()) { + assert(fixed_buffer_[fixed_buffer_used_size_] == '\0'); + glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); + } + glowable_buffer_ += c; + } } - if (hFile_ != INVALID_HANDLE_VALUE) { - ::CloseHandle(hFile_); - hFile_ = INVALID_HANDLE_VALUE; - } -#else - if (addr_ != nullptr) { - munmap(addr_, size_); - addr_ = nullptr; - } + Stream &strm_; + char *fixed_buffer_; + const size_t fixed_buffer_size_; + size_t fixed_buffer_used_size_; + std::string glowable_buffer_; +}; - if (fd_ != -1) { - ::close(fd_); - fd_ = -1; - } -#endif - size_ = 0; -} inline int close_socket(socket_t sock) { #ifdef _WIN32 return closesocket(sock); @@ -2768,125 +718,19 @@ inline int close_socket(socket_t sock) { #endif } -template inline ssize_t handle_EINTR(T fn) { - ssize_t res = 0; - while (true) { - res = fn(); - if (res < 0 && errno == EINTR) { continue; } - break; - } - return res; -} - -inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) { - return handle_EINTR([&]() { - return recv(sock, -#ifdef _WIN32 - static_cast(ptr), static_cast(size), -#else - ptr, size, -#endif - flags); - }); -} - -inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size, - int flags) { - return handle_EINTR([&]() { - return send(sock, -#ifdef _WIN32 - static_cast(ptr), static_cast(size), -#else - ptr, size, -#endif - flags); - }); -} - -inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) { -#ifdef CPPHTTPLIB_USE_POLL - struct pollfd pfd_read; - pfd_read.fd = sock; - pfd_read.events = POLLIN; - - auto timeout = static_cast(sec * 1000 + usec / 1000); - - return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); -#else -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { return -1; } -#endif - +inline int select_read(socket_t sock, time_t sec, time_t usec) { fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds); timeval tv; tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); + tv.tv_usec = static_cast(usec); - return handle_EINTR([&]() { - return select(static_cast(sock + 1), &fds, nullptr, nullptr, &tv); - }); -#endif + return select(static_cast(sock + 1), &fds, nullptr, nullptr, &tv); } -inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) { -#ifdef CPPHTTPLIB_USE_POLL - struct pollfd pfd_read; - pfd_read.fd = sock; - pfd_read.events = POLLOUT; - - auto timeout = static_cast(sec * 1000 + usec / 1000); - - return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); -#else -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { return -1; } -#endif - - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock, &fds); - - timeval tv; - tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); - - return handle_EINTR([&]() { - return select(static_cast(sock + 1), nullptr, &fds, nullptr, &tv); - }); -#endif -} - -inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, - time_t usec) { -#ifdef CPPHTTPLIB_USE_POLL - struct pollfd pfd_read; - pfd_read.fd = sock; - pfd_read.events = POLLIN | POLLOUT; - - auto timeout = static_cast(sec * 1000 + usec / 1000); - - auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); }); - - if (poll_res == 0) { return Error::ConnectionTimeout; } - - if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) { - auto error = 0; - socklen_t len = sizeof(error); - auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, - reinterpret_cast(&error), &len); - auto successful = res >= 0 && !error; - return successful ? Error::Success : Error::Connection; - } - - return Error::Connection; -#else -#ifndef _WIN32 - if (sock >= FD_SETSIZE) { return Error::Connection; } -#endif - +inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { fd_set fdsr; FD_ZERO(&fdsr); FD_SET(sock, &fdsr); @@ -2896,155 +740,53 @@ inline Error wait_until_socket_is_ready(socket_t sock, time_t sec, timeval tv; tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); + tv.tv_usec = static_cast(usec); - auto ret = handle_EINTR([&]() { - return select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv); - }); - - if (ret == 0) { return Error::ConnectionTimeout; } - - if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) { - auto error = 0; + if (select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv) < 0) { + return false; + } else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) { + int error = 0; socklen_t len = sizeof(error); - auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR, - reinterpret_cast(&error), &len); - auto successful = res >= 0 && !error; - return successful ? Error::Success : Error::Connection; - } - return Error::Connection; -#endif -} - -inline bool is_socket_alive(socket_t sock) { - const auto val = detail::select_read(sock, 0, 0); - if (val == 0) { - return true; - } else if (val < 0 && errno == EBADF) { + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0 || + error) { + return false; + } + } else { return false; } - char buf[1]; - return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0; + + return true; } -class SocketStream : public Stream { -public: - SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec, - time_t write_timeout_sec, time_t write_timeout_usec); - ~SocketStream() override; +template +inline bool read_and_close_socket(socket_t sock, size_t keep_alive_max_count, + T callback) { + bool ret = false; - bool is_readable() const override; - bool is_writable() const override; - ssize_t read(char *ptr, size_t size) override; - ssize_t write(const char *ptr, size_t size) override; - void get_remote_ip_and_port(std::string &ip, int &port) const override; - void get_local_ip_and_port(std::string &ip, int &port) const override; - socket_t socket() const override; + if (keep_alive_max_count > 0) { + auto count = keep_alive_max_count; + while (count > 0 && + detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND, + CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0) { + SocketStream strm(sock); + auto last_connection = count == 1; + auto connection_close = false; -private: - socket_t sock_; - time_t read_timeout_sec_; - time_t read_timeout_usec_; - time_t write_timeout_sec_; - time_t write_timeout_usec_; + ret = callback(strm, last_connection, connection_close); + if (!ret || connection_close) { break; } - std::vector read_buff_; - size_t read_buff_off_ = 0; - size_t read_buff_content_size_ = 0; - - static const size_t read_buff_size_ = 1024l * 4; -}; - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -class SSLSocketStream : public Stream { -public: - SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec, - time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec); - ~SSLSocketStream() override; - - bool is_readable() const override; - bool is_writable() const override; - ssize_t read(char *ptr, size_t size) override; - ssize_t write(const char *ptr, size_t size) override; - void get_remote_ip_and_port(std::string &ip, int &port) const override; - void get_local_ip_and_port(std::string &ip, int &port) const override; - socket_t socket() const override; - -private: - socket_t sock_; - SSL *ssl_; - time_t read_timeout_sec_; - time_t read_timeout_usec_; - time_t write_timeout_sec_; - time_t write_timeout_usec_; -}; -#endif - -inline bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) { - using namespace std::chrono; - auto start = steady_clock::now(); - while (true) { - auto val = select_read(sock, 0, 10000); - if (val < 0) { - return false; - } else if (val == 0) { - auto current = steady_clock::now(); - auto duration = duration_cast(current - start); - auto timeout = keep_alive_timeout_sec * 1000; - if (duration.count() > timeout) { return false; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } else { - return true; + count--; } + } else { + SocketStream strm(sock); + auto dummy_connection_close = false; + ret = callback(strm, true, dummy_connection_close); } -} -template -inline bool -process_server_socket_core(const std::atomic &svr_sock, socket_t sock, - size_t keep_alive_max_count, - time_t keep_alive_timeout_sec, T callback) { - assert(keep_alive_max_count > 0); - auto ret = false; - auto count = keep_alive_max_count; - while (svr_sock != INVALID_SOCKET && count > 0 && - keep_alive(sock, keep_alive_timeout_sec)) { - auto close_connection = count == 1; - auto connection_closed = false; - ret = callback(close_connection, connection_closed); - if (!ret || connection_closed) { break; } - count--; - } + close_socket(sock); return ret; } -template -inline bool -process_server_socket(const std::atomic &svr_sock, socket_t sock, - size_t keep_alive_max_count, - time_t keep_alive_timeout_sec, time_t read_timeout_sec, - time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec, T callback) { - return process_server_socket_core( - svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec, - [&](bool close_connection, bool &connection_closed) { - SocketStream strm(sock, read_timeout_sec, read_timeout_usec, - write_timeout_sec, write_timeout_usec); - return callback(strm, close_connection, connection_closed); - }); -} - -inline bool process_client_socket(socket_t sock, time_t read_timeout_sec, - time_t read_timeout_usec, - time_t write_timeout_sec, - time_t write_timeout_usec, - std::function callback) { - SocketStream strm(sock, read_timeout_sec, read_timeout_usec, - write_timeout_sec, write_timeout_usec); - return callback(strm); -} - inline int shutdown_socket(socket_t sock) { #ifdef _WIN32 return shutdown(sock, SD_BOTH); @@ -3053,128 +795,57 @@ inline int shutdown_socket(socket_t sock) { #endif } -template -socket_t create_socket(const std::string &host, const std::string &ip, int port, - int address_family, int socket_flags, bool tcp_nodelay, - SocketOptions socket_options, - BindOrConnect bind_or_connect) { +template +socket_t create_socket(const char *host, int port, Fn fn, + int socket_flags = 0) { +#ifdef _WIN32 +#define SO_SYNCHRONOUS_NONALERT 0x20 +#define SO_OPENTYPE 0x7008 + + int opt = SO_SYNCHRONOUS_NONALERT; + setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, + sizeof(opt)); +#endif + // Get address info - const char *node = nullptr; struct addrinfo hints; struct addrinfo *result; memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = socket_flags; hints.ai_protocol = 0; - if (!ip.empty()) { - node = ip.c_str(); - // Ask getaddrinfo to convert IP in c-string to address - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_NUMERICHOST; - } else { - if (!host.empty()) { node = host.c_str(); } - hints.ai_family = address_family; - hints.ai_flags = socket_flags; - } - -#ifndef _WIN32 - if (hints.ai_family == AF_UNIX) { - const auto addrlen = host.length(); - if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; } - - auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); - if (sock != INVALID_SOCKET) { - sockaddr_un addr{}; - addr.sun_family = AF_UNIX; - std::copy(host.begin(), host.end(), addr.sun_path); - - hints.ai_addr = reinterpret_cast(&addr); - hints.ai_addrlen = static_cast( - sizeof(addr) - sizeof(addr.sun_path) + addrlen); - - fcntl(sock, F_SETFD, FD_CLOEXEC); - if (socket_options) { socket_options(sock); } - - if (!bind_or_connect(sock, hints)) { - close_socket(sock); - sock = INVALID_SOCKET; - } - } - return sock; - } -#endif - auto service = std::to_string(port); - if (getaddrinfo(node, service.c_str(), &hints, &result)) { -#if defined __linux__ && !defined __ANDROID__ - res_init(); -#endif + if (getaddrinfo(host, service.c_str(), &hints, &result)) { return INVALID_SOCKET; } for (auto rp = result; rp; rp = rp->ai_next) { // Create a socket #ifdef _WIN32 - auto sock = - WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0, - WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED); - /** - * Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1 - * and above the socket creation fails on older Windows Systems. - * - * Let's try to create a socket the old way in this case. - * - * Reference: - * https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa - * - * WSA_FLAG_NO_HANDLE_INHERIT: - * This flag is supported on Windows 7 with SP1, Windows Server 2008 R2 with - * SP1, and later - * - */ - if (sock == INVALID_SOCKET) { - sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - } + auto sock = WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, + nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT); #else auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); #endif if (sock == INVALID_SOCKET) { continue; } #ifndef _WIN32 - if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { - close_socket(sock); - continue; - } + if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { continue; } #endif - if (tcp_nodelay) { - auto yes = 1; -#ifdef _WIN32 - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&yes), sizeof(yes)); -#else - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&yes), sizeof(yes)); + // Make 'reuse address' option available + int yes = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); +#ifdef SO_REUSEPORT + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&yes, sizeof(yes)); #endif - } - - if (socket_options) { socket_options(sock); } - - if (rp->ai_family == AF_INET6) { - auto no = 0; -#ifdef _WIN32 - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast(&no), sizeof(no)); -#else - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast(&no), sizeof(no)); -#endif - } // bind or connect - if (bind_or_connect(sock, *rp)) { + if (fn(sock, *rp)) { freeaddrinfo(result); return sock; } @@ -3205,659 +876,229 @@ inline bool is_connection_error() { #endif } -inline bool bind_ip_address(socket_t sock, const std::string &host) { - struct addrinfo hints; - struct addrinfo *result; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; } - - auto ret = false; - for (auto rp = result; rp; rp = rp->ai_next) { - const auto &ai = *rp; - if (!::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { - ret = true; - break; - } - } - - freeaddrinfo(result); - return ret; -} - -#if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__ -#define USE_IF2IP -#endif - -#ifdef USE_IF2IP -inline std::string if2ip(int address_family, const std::string &ifn) { - struct ifaddrs *ifap; - getifaddrs(&ifap); - std::string addr_candidate; - for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_addr && ifn == ifa->ifa_name && - (AF_UNSPEC == address_family || - ifa->ifa_addr->sa_family == address_family)) { - if (ifa->ifa_addr->sa_family == AF_INET) { - auto sa = reinterpret_cast(ifa->ifa_addr); - char buf[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) { - freeifaddrs(ifap); - return std::string(buf, INET_ADDRSTRLEN); - } - } else if (ifa->ifa_addr->sa_family == AF_INET6) { - auto sa = reinterpret_cast(ifa->ifa_addr); - if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) { - char buf[INET6_ADDRSTRLEN] = {}; - if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) { - // equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL - auto s6_addr_head = sa->sin6_addr.s6_addr[0]; - if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) { - addr_candidate = std::string(buf, INET6_ADDRSTRLEN); - } else { - freeifaddrs(ifap); - return std::string(buf, INET6_ADDRSTRLEN); - } - } - } - } - } - } - freeifaddrs(ifap); - return addr_candidate; -} -#endif - -inline socket_t create_client_socket( - const std::string &host, const std::string &ip, int port, - int address_family, bool tcp_nodelay, SocketOptions socket_options, - time_t connection_timeout_sec, time_t connection_timeout_usec, - time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec, const std::string &intf, Error &error) { - auto sock = create_socket( - host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options), - [&](socket_t sock2, struct addrinfo &ai) -> bool { - if (!intf.empty()) { -#ifdef USE_IF2IP - auto ip_from_if = if2ip(address_family, intf); - if (ip_from_if.empty()) { ip_from_if = intf; } - if (!bind_ip_address(sock2, ip_from_if)) { - error = Error::BindIPAddress; - return false; - } -#endif - } - - set_nonblocking(sock2, true); - - auto ret = - ::connect(sock2, ai.ai_addr, static_cast(ai.ai_addrlen)); - - if (ret < 0) { - if (is_connection_error()) { - error = Error::Connection; - return false; - } - error = wait_until_socket_is_ready(sock2, connection_timeout_sec, - connection_timeout_usec); - if (error != Error::Success) { return false; } - } - - set_nonblocking(sock2, false); - - { -#ifdef _WIN32 - auto timeout = static_cast(read_timeout_sec * 1000 + - read_timeout_usec / 1000); - setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(read_timeout_sec); - tv.tv_usec = static_cast(read_timeout_usec); - setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } - { - -#ifdef _WIN32 - auto timeout = static_cast(write_timeout_sec * 1000 + - write_timeout_usec / 1000); - setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(write_timeout_sec); - tv.tv_usec = static_cast(write_timeout_usec); - setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } - - error = Error::Success; - return true; - }); - - if (sock != INVALID_SOCKET) { - error = Error::Success; - } else { - if (error == Error::Success) { error = Error::Connection; } - } - - return sock; -} - -inline bool get_ip_and_port(const struct sockaddr_storage &addr, - socklen_t addr_len, std::string &ip, int &port) { - if (addr.ss_family == AF_INET) { - port = ntohs(reinterpret_cast(&addr)->sin_port); - } else if (addr.ss_family == AF_INET6) { - port = - ntohs(reinterpret_cast(&addr)->sin6_port); - } else { - return false; - } - - std::array ipstr{}; - if (getnameinfo(reinterpret_cast(&addr), addr_len, - ipstr.data(), static_cast(ipstr.size()), nullptr, - 0, NI_NUMERICHOST)) { - return false; - } - - ip = ipstr.data(); - return true; -} - -inline void get_local_ip_and_port(socket_t sock, std::string &ip, int &port) { +inline std::string get_remote_addr(socket_t sock) { struct sockaddr_storage addr; - socklen_t addr_len = sizeof(addr); - if (!getsockname(sock, reinterpret_cast(&addr), - &addr_len)) { - get_ip_and_port(addr, addr_len, ip, port); - } -} + socklen_t len = sizeof(addr); -inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) { - struct sockaddr_storage addr; - socklen_t addr_len = sizeof(addr); + if (!getpeername(sock, (struct sockaddr *)&addr, &len)) { + char ipstr[NI_MAXHOST]; - if (!getpeername(sock, reinterpret_cast(&addr), - &addr_len)) { -#ifndef _WIN32 - if (addr.ss_family == AF_UNIX) { -#if defined(__linux__) - struct ucred ucred; - socklen_t len = sizeof(ucred); - if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) { - port = ucred.pid; - } -#elif defined(SOL_LOCAL) && defined(SO_PEERPID) // __APPLE__ - pid_t pid; - socklen_t len = sizeof(pid); - if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) { - port = pid; - } -#endif - return; + if (!getnameinfo((struct sockaddr *)&addr, len, ipstr, sizeof(ipstr), + nullptr, 0, NI_NUMERICHOST)) { + return ipstr; } -#endif - get_ip_and_port(addr, addr_len, ip, port); } + + return std::string(); } -inline constexpr unsigned int str2tag_core(const char *s, size_t l, - unsigned int h) { - return (l == 0) - ? h - : str2tag_core( - s + 1, l - 1, - // Unsets the 6 high bits of h, therefore no overflow happens - (((std::numeric_limits::max)() >> 6) & - h * 33) ^ - static_cast(*s)); -} - -inline unsigned int str2tag(const std::string &s) { - return str2tag_core(s.data(), s.size(), 0); -} - -namespace udl { - -inline constexpr unsigned int operator"" _t(const char *s, size_t l) { - return str2tag_core(s, l, 0); -} - -} // namespace udl - -inline std::string -find_content_type(const std::string &path, - const std::map &user_data, - const std::string &default_content_type) { +inline const char *find_content_type(const std::string &path) { auto ext = file_extension(path); - - auto it = user_data.find(ext); - if (it != user_data.end()) { return it->second; } - - using udl::operator""_t; - - switch (str2tag(ext)) { - default: return default_content_type; - - case "css"_t: return "text/css"; - case "csv"_t: return "text/csv"; - case "htm"_t: - case "html"_t: return "text/html"; - case "js"_t: - case "mjs"_t: return "text/javascript"; - case "txt"_t: return "text/plain"; - case "vtt"_t: return "text/vtt"; - - case "apng"_t: return "image/apng"; - case "avif"_t: return "image/avif"; - case "bmp"_t: return "image/bmp"; - case "gif"_t: return "image/gif"; - case "png"_t: return "image/png"; - case "svg"_t: return "image/svg+xml"; - case "webp"_t: return "image/webp"; - case "ico"_t: return "image/x-icon"; - case "tif"_t: return "image/tiff"; - case "tiff"_t: return "image/tiff"; - case "jpg"_t: - case "jpeg"_t: return "image/jpeg"; - - case "mp4"_t: return "video/mp4"; - case "mpeg"_t: return "video/mpeg"; - case "webm"_t: return "video/webm"; - - case "mp3"_t: return "audio/mp3"; - case "mpga"_t: return "audio/mpeg"; - case "weba"_t: return "audio/webm"; - case "wav"_t: return "audio/wave"; - - case "otf"_t: return "font/otf"; - case "ttf"_t: return "font/ttf"; - case "woff"_t: return "font/woff"; - case "woff2"_t: return "font/woff2"; - - case "7z"_t: return "application/x-7z-compressed"; - case "atom"_t: return "application/atom+xml"; - case "pdf"_t: return "application/pdf"; - case "json"_t: return "application/json"; - case "rss"_t: return "application/rss+xml"; - case "tar"_t: return "application/x-tar"; - case "xht"_t: - case "xhtml"_t: return "application/xhtml+xml"; - case "xslt"_t: return "application/xslt+xml"; - case "xml"_t: return "application/xml"; - case "gz"_t: return "application/gzip"; - case "zip"_t: return "application/zip"; - case "wasm"_t: return "application/wasm"; + if (ext == "txt") { + return "text/plain"; + } else if (ext == "html") { + return "text/html"; + } else if (ext == "css") { + return "text/css"; + } else if (ext == "jpeg" || ext == "jpg") { + return "image/jpg"; + } else if (ext == "png") { + return "image/png"; + } else if (ext == "gif") { + return "image/gif"; + } else if (ext == "svg") { + return "image/svg+xml"; + } else if (ext == "ico") { + return "image/x-icon"; + } else if (ext == "json") { + return "application/json"; + } else if (ext == "pdf") { + return "application/pdf"; + } else if (ext == "js") { + return "application/javascript"; + } else if (ext == "xml") { + return "application/xml"; + } else if (ext == "xhtml") { + return "application/xhtml+xml"; } + return nullptr; } -inline bool can_compress_content_type(const std::string &content_type) { - using udl::operator""_t; - - auto tag = str2tag(content_type); - - switch (tag) { - case "image/svg+xml"_t: - case "application/javascript"_t: - case "application/json"_t: - case "application/xml"_t: - case "application/protobuf"_t: - case "application/xhtml+xml"_t: return true; - +inline const char *status_message(int status) { + switch (status) { + case 200: return "OK"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 400: return "Bad Request"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 413: return "Payload Too Large"; + case 414: return "Request-URI Too Long"; + case 415: return "Unsupported Media Type"; default: - return !content_type.rfind("text/", 0) && tag != "text/event-stream"_t; + case 500: return "Internal Server Error"; } } -inline EncodingType encoding_type(const Request &req, const Response &res) { - auto ret = - detail::can_compress_content_type(res.get_header_value("Content-Type")); - if (!ret) { return EncodingType::None; } - - const auto &s = req.get_header_value("Accept-Encoding"); - (void)(s); - -#ifdef CPPHTTPLIB_BROTLI_SUPPORT - // TODO: 'Accept-Encoding' has br, not br;q=0 - ret = s.find("br") != std::string::npos; - if (ret) { return EncodingType::Brotli; } -#endif - #ifdef CPPHTTPLIB_ZLIB_SUPPORT - // TODO: 'Accept-Encoding' has gzip, not gzip;q=0 - ret = s.find("gzip") != std::string::npos; - if (ret) { return EncodingType::Gzip; } -#endif - - return EncodingType::None; +inline bool can_compress(const std::string &content_type) { + return !content_type.find("text/") || content_type == "image/svg+xml" || + content_type == "application/javascript" || + content_type == "application/json" || + content_type == "application/xml" || + content_type == "application/xhtml+xml"; } -inline bool nocompressor::compress(const char *data, size_t data_length, - bool /*last*/, Callback callback) { - if (!data_length) { return true; } - return callback(data, data_length); -} +inline bool compress(std::string &content) { + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; -#ifdef CPPHTTPLIB_ZLIB_SUPPORT -inline gzip_compressor::gzip_compressor() { - std::memset(&strm_, 0, sizeof(strm_)); - strm_.zalloc = Z_NULL; - strm_.zfree = Z_NULL; - strm_.opaque = Z_NULL; + auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, + Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { return false; } - is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, - Z_DEFAULT_STRATEGY) == Z_OK; -} + strm.avail_in = content.size(); + strm.next_in = (Bytef *)content.data(); -inline gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); } - -inline bool gzip_compressor::compress(const char *data, size_t data_length, - bool last, Callback callback) { - assert(is_valid_); + std::string compressed; + const auto bufsiz = 16384; + char buff[bufsiz]; do { - constexpr size_t max_avail_in = - (std::numeric_limits::max)(); + strm.avail_out = bufsiz; + strm.next_out = (Bytef *)buff; + ret = deflate(&strm, Z_FINISH); + assert(ret != Z_STREAM_ERROR); + compressed.append(buff, bufsiz - strm.avail_out); + } while (strm.avail_out == 0); - strm_.avail_in = static_cast( - (std::min)(data_length, max_avail_in)); - strm_.next_in = const_cast(reinterpret_cast(data)); + assert(ret == Z_STREAM_END); + assert(strm.avail_in == 0); - data_length -= strm_.avail_in; - data += strm_.avail_in; - - auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH; - auto ret = Z_OK; - - std::array buff{}; - do { - strm_.avail_out = static_cast(buff.size()); - strm_.next_out = reinterpret_cast(buff.data()); - - ret = deflate(&strm_, flush); - if (ret == Z_STREAM_ERROR) { return false; } - - if (!callback(buff.data(), buff.size() - strm_.avail_out)) { - return false; - } - } while (strm_.avail_out == 0); - - assert((flush == Z_FINISH && ret == Z_STREAM_END) || - (flush == Z_NO_FLUSH && ret == Z_OK)); - assert(strm_.avail_in == 0); - } while (data_length > 0); + content.swap(compressed); + deflateEnd(&strm); return true; } -inline gzip_decompressor::gzip_decompressor() { - std::memset(&strm_, 0, sizeof(strm_)); - strm_.zalloc = Z_NULL; - strm_.zfree = Z_NULL; - strm_.opaque = Z_NULL; +class decompressor { +public: + decompressor() { + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; - // 15 is the value of wbits, which should be at the maximum possible value - // to ensure that any gzip stream can be decoded. The offset of 32 specifies - // that the stream type should be automatically detected either gzip or - // deflate. - is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK; -} + // 15 is the value of wbits, which should be at the maximum possible value + // to ensure that any gzip stream can be decoded. The offset of 16 specifies + // that the stream to decompress will be formatted with a gzip wrapper. + is_valid_ = inflateInit2(&strm, 16 + 15) == Z_OK; + } -inline gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); } + ~decompressor() { inflateEnd(&strm); } -inline bool gzip_decompressor::is_valid() const { return is_valid_; } + bool is_valid() const { return is_valid_; } -inline bool gzip_decompressor::decompress(const char *data, size_t data_length, - Callback callback) { - assert(is_valid_); + template + bool decompress(const char *data, size_t data_len, T callback) { + int ret = Z_OK; + std::string decompressed; - auto ret = Z_OK; + // strm.avail_in = content.size(); + // strm.next_in = (Bytef *)content.data(); + strm.avail_in = data_len; + strm.next_in = (Bytef *)data; - do { - constexpr size_t max_avail_in = - (std::numeric_limits::max)(); - - strm_.avail_in = static_cast( - (std::min)(data_length, max_avail_in)); - strm_.next_in = const_cast(reinterpret_cast(data)); - - data_length -= strm_.avail_in; - data += strm_.avail_in; - - std::array buff{}; - while (strm_.avail_in > 0 && ret == Z_OK) { - strm_.avail_out = static_cast(buff.size()); - strm_.next_out = reinterpret_cast(buff.data()); - - ret = inflate(&strm_, Z_NO_FLUSH); + const auto bufsiz = 16384; + char buff[bufsiz]; + do { + strm.avail_out = bufsiz; + strm.next_out = (Bytef *)buff; + ret = inflate(&strm, Z_NO_FLUSH); assert(ret != Z_STREAM_ERROR); switch (ret) { case Z_NEED_DICT: case Z_DATA_ERROR: - case Z_MEM_ERROR: inflateEnd(&strm_); return false; + case Z_MEM_ERROR: inflateEnd(&strm); return false; } - if (!callback(buff.data(), buff.size() - strm_.avail_out)) { - return false; - } + decompressed.append(buff, bufsiz - strm.avail_out); + } while (strm.avail_out == 0); + + if (ret == Z_STREAM_END) { + callback(decompressed.data(), decompressed.size()); + return true; } - if (ret != Z_OK && ret != Z_STREAM_END) { return false; } + return false; + } - } while (data_length > 0); - - return true; -} +private: + bool is_valid_; + z_stream strm; +}; #endif -#ifdef CPPHTTPLIB_BROTLI_SUPPORT -inline brotli_compressor::brotli_compressor() { - state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr); -} - -inline brotli_compressor::~brotli_compressor() { - BrotliEncoderDestroyInstance(state_); -} - -inline bool brotli_compressor::compress(const char *data, size_t data_length, - bool last, Callback callback) { - std::array buff{}; - - auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS; - auto available_in = data_length; - auto next_in = reinterpret_cast(data); - - for (;;) { - if (last) { - if (BrotliEncoderIsFinished(state_)) { break; } - } else { - if (!available_in) { break; } - } - - auto available_out = buff.size(); - auto next_out = buff.data(); - - if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in, - &available_out, &next_out, nullptr)) { - return false; - } - - auto output_bytes = buff.size() - available_out; - if (output_bytes) { - callback(reinterpret_cast(buff.data()), output_bytes); - } - } - - return true; -} - -inline brotli_decompressor::brotli_decompressor() { - decoder_s = BrotliDecoderCreateInstance(0, 0, 0); - decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT - : BROTLI_DECODER_RESULT_ERROR; -} - -inline brotli_decompressor::~brotli_decompressor() { - if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); } -} - -inline bool brotli_decompressor::is_valid() const { return decoder_s; } - -inline bool brotli_decompressor::decompress(const char *data, - size_t data_length, - Callback callback) { - if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS || - decoder_r == BROTLI_DECODER_RESULT_ERROR) { - return 0; - } - - auto next_in = reinterpret_cast(data); - size_t avail_in = data_length; - size_t total_out; - - decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; - - std::array buff{}; - while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { - char *next_out = buff.data(); - size_t avail_out = buff.size(); - - decoder_r = BrotliDecoderDecompressStream( - decoder_s, &avail_in, &next_in, &avail_out, - reinterpret_cast(&next_out), &total_out); - - if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; } - - if (!callback(buff.data(), buff.size() - avail_out)) { return false; } - } - - return decoder_r == BROTLI_DECODER_RESULT_SUCCESS || - decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT; -} -#endif - -inline bool has_header(const Headers &headers, const std::string &key) { +inline bool has_header(const Headers &headers, const char *key) { return headers.find(key) != headers.end(); } -inline const char *get_header_value(const Headers &headers, - const std::string &key, size_t id, - const char *def) { - auto rng = headers.equal_range(key); - auto it = rng.first; - std::advance(it, static_cast(id)); - if (it != rng.second) { return it->second.c_str(); } +inline const char *get_header_value(const Headers &headers, const char *key, + size_t id = 0, const char *def = nullptr) { + auto it = headers.find(key); + std::advance(it, id); + if (it != headers.end()) { return it->second.c_str(); } return def; } -inline bool compare_case_ignore(const std::string &a, const std::string &b) { - if (a.size() != b.size()) { return false; } - for (size_t i = 0; i < b.size(); i++) { - if (::tolower(a[i]) != ::tolower(b[i])) { return false; } +inline uint64_t get_header_value_uint64(const Headers &headers, const char *key, + int def = 0) { + auto it = headers.find(key); + if (it != headers.end()) { + return std::strtoull(it->second.data(), nullptr, 10); } + return def; +} + +inline bool read_headers(Stream &strm, Headers &headers) { + static std::regex re(R"((.+?):\s*(.+?)\s*\r\n)"); + + const auto bufsiz = 2048; + char buf[bufsiz]; + + stream_line_reader reader(strm, buf, bufsiz); + + for (;;) { + if (!reader.getline()) { return false; } + if (!strcmp(reader.ptr(), "\r\n")) { break; } + std::cmatch m; + if (std::regex_match(reader.ptr(), m, re)) { + auto key = std::string(m[1]); + auto val = std::string(m[2]); + headers.emplace(key, val); + } + } + return true; } template -inline bool parse_header(const char *beg, const char *end, T fn) { - // Skip trailing spaces and tabs. - while (beg < end && is_space_or_tab(end[-1])) { - end--; - } - - auto p = beg; - while (p < end && *p != ':') { - p++; - } - - if (p == end) { return false; } - - auto key_end = p; - - if (*p++ != ':') { return false; } - - while (p < end && is_space_or_tab(*p)) { - p++; - } - - if (p < end) { - auto key_len = key_end - beg; - if (!key_len) { return false; } - - auto key = std::string(beg, key_end); - auto val = compare_case_ignore(key, "Location") - ? std::string(p, end) - : decode_url(std::string(p, end), false); - fn(std::move(key), std::move(val)); - return true; - } - - return false; -} - -inline bool read_headers(Stream &strm, Headers &headers) { - const auto bufsiz = 2048; - char buf[bufsiz]; - stream_line_reader line_reader(strm, buf, bufsiz); - - for (;;) { - if (!line_reader.getline()) { return false; } - - // Check if the line ends with CRLF. - auto line_terminator_len = 2; - if (line_reader.end_with_crlf()) { - // Blank line indicates end of headers. - if (line_reader.size() == 2) { break; } -#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR - } else { - // Blank line indicates end of headers. - if (line_reader.size() == 1) { break; } - line_terminator_len = 1; - } -#else - } else { - continue; // Skip invalid line. - } -#endif - - if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } - - // Exclude line terminator - auto end = line_reader.ptr() + line_reader.size() - line_terminator_len; - - parse_header(line_reader.ptr(), end, - [&](std::string &&key, std::string &&val) { - headers.emplace(std::move(key), std::move(val)); - }); - } - - return true; -} - -inline bool read_content_with_length(Stream &strm, uint64_t len, - Progress progress, - ContentReceiverWithProgress out) { +inline bool read_content_with_length(Stream &strm, size_t len, + Progress progress, T callback) { char buf[CPPHTTPLIB_RECV_BUFSIZ]; - uint64_t r = 0; + size_t r = 0; while (r < len) { - auto read_len = static_cast(len - r); - auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ)); + auto n = strm.read(buf, std::min((len - r), CPPHTTPLIB_RECV_BUFSIZ)); if (n <= 0) { return false; } - if (!out(buf, static_cast(n), r, len)) { return false; } - r += static_cast(n); + callback(buf, n); + + r += n; if (progress) { if (!progress(r, len)) { return false; } @@ -3867,2053 +1108,612 @@ inline bool read_content_with_length(Stream &strm, uint64_t len, return true; } -inline void skip_content_with_length(Stream &strm, uint64_t len) { +inline void skip_content_with_length(Stream &strm, size_t len) { char buf[CPPHTTPLIB_RECV_BUFSIZ]; - uint64_t r = 0; + size_t r = 0; while (r < len) { - auto read_len = static_cast(len - r); - auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ)); + auto n = strm.read(buf, std::min((len - r), CPPHTTPLIB_RECV_BUFSIZ)); if (n <= 0) { return; } - r += static_cast(n); + r += n; } } -inline bool read_content_without_length(Stream &strm, - ContentReceiverWithProgress out) { +template +inline bool read_content_without_length(Stream &strm, T callback) { char buf[CPPHTTPLIB_RECV_BUFSIZ]; - uint64_t r = 0; for (;;) { auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ); - if (n <= 0) { return true; } - - if (!out(buf, static_cast(n), r, 0)) { return false; } - r += static_cast(n); + if (n < 0) { + return false; + } else if (n == 0) { + return true; + } + callback(buf, n); } return true; } template -inline bool read_content_chunked(Stream &strm, T &x, - ContentReceiverWithProgress out) { +inline bool read_content_chunked(Stream &strm, T callback) { const auto bufsiz = 16; char buf[bufsiz]; - stream_line_reader line_reader(strm, buf, bufsiz); + stream_line_reader reader(strm, buf, bufsiz); - if (!line_reader.getline()) { return false; } + if (!reader.getline()) { return false; } - unsigned long chunk_len; - while (true) { - char *end_ptr; + auto chunk_len = std::stoi(reader.ptr(), 0, 16); - chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16); - - if (end_ptr == line_reader.ptr()) { return false; } - if (chunk_len == ULONG_MAX) { return false; } - - if (chunk_len == 0) { break; } - - if (!read_content_with_length(strm, chunk_len, nullptr, out)) { + while (chunk_len > 0) { + if (!read_content_with_length(strm, chunk_len, nullptr, callback)) { return false; } - if (!line_reader.getline()) { return false; } + if (!reader.getline()) { return false; } - if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; } + if (strcmp(reader.ptr(), "\r\n")) { break; } - if (!line_reader.getline()) { return false; } + if (!reader.getline()) { return false; } + + chunk_len = std::stoi(reader.ptr(), 0, 16); } - assert(chunk_len == 0); - - // Trailer - if (!line_reader.getline()) { return false; } - - while (strcmp(line_reader.ptr(), "\r\n") != 0) { - if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } - - // Exclude line terminator - constexpr auto line_terminator_len = 2; - auto end = line_reader.ptr() + line_reader.size() - line_terminator_len; - - parse_header(line_reader.ptr(), end, - [&](std::string &&key, std::string &&val) { - x.headers.emplace(std::move(key), std::move(val)); - }); - - if (!line_reader.getline()) { return false; } + if (chunk_len == 0) { + // Reader terminator after chunks + if (!reader.getline() || strcmp(reader.ptr(), "\r\n")) return false; } return true; } inline bool is_chunked_transfer_encoding(const Headers &headers) { - return compare_case_ignore( - get_header_value(headers, "Transfer-Encoding", 0, ""), "chunked"); + return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""), + "chunked"); } template -bool prepare_content_receiver(T &x, int &status, - ContentReceiverWithProgress receiver, - bool decompress, U callback) { - if (decompress) { - std::string encoding = x.get_header_value("Content-Encoding"); - std::unique_ptr decompressor; +bool read_content(Stream &strm, T &x, uint64_t payload_max_length, int &status, + Progress progress, U callback) { + + ContentReceiver out = [&](const char *buf, size_t n) { callback(buf, n); }; - if (encoding == "gzip" || encoding == "deflate") { #ifdef CPPHTTPLIB_ZLIB_SUPPORT - decompressor = detail::make_unique(); + detail::decompressor decompressor; + + if (!decompressor.is_valid()) { + status = 500; + return false; + } + + if (x.get_header_value("Content-Encoding") == "gzip") { + out = [&](const char *buf, size_t n) { + decompressor.decompress( + buf, n, [&](const char *buf, size_t n) { callback(buf, n); }); + }; + } #else - status = StatusCode::UnsupportedMediaType_415; - return false; + if (x.get_header_value("Content-Encoding") == "gzip") { + status = 415; + return false; + } #endif - } else if (encoding.find("br") != std::string::npos) { -#ifdef CPPHTTPLIB_BROTLI_SUPPORT - decompressor = detail::make_unique(); -#else - status = StatusCode::UnsupportedMediaType_415; - return false; -#endif - } - if (decompressor) { - if (decompressor->is_valid()) { - ContentReceiverWithProgress out = [&](const char *buf, size_t n, - uint64_t off, uint64_t len) { - return decompressor->decompress(buf, n, - [&](const char *buf2, size_t n2) { - return receiver(buf2, n2, off, len); - }); - }; - return callback(std::move(out)); + auto ret = true; + auto exceed_payload_max_length = false; + + if (is_chunked_transfer_encoding(x.headers)) { + ret = read_content_chunked(strm, out); + } else if (!has_header(x.headers, "Content-Length")) { + ret = read_content_without_length(strm, out); + } else { + auto len = get_header_value_uint64(x.headers, "Content-Length", 0); + if (len > 0) { + if ((len > payload_max_length) || + // For 32-bit platform + (sizeof(size_t) < sizeof(uint64_t) && + len > std::numeric_limits::max())) { + exceed_payload_max_length = true; + skip_content_with_length(strm, len); + ret = false; } else { - status = StatusCode::InternalServerError_500; - return false; + ret = read_content_with_length(strm, len, progress, out); } } } - ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off, - uint64_t len) { - return receiver(buf, n, off, len); - }; - return callback(std::move(out)); -} + if (!ret) { status = exceed_payload_max_length ? 413 : 400; } -template -bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, - Progress progress, ContentReceiverWithProgress receiver, - bool decompress) { - return prepare_content_receiver( - x, status, std::move(receiver), decompress, - [&](const ContentReceiverWithProgress &out) { - auto ret = true; - auto exceed_payload_max_length = false; - - if (is_chunked_transfer_encoding(x.headers)) { - ret = read_content_chunked(strm, x, out); - } else if (!has_header(x.headers, "Content-Length")) { - ret = read_content_without_length(strm, out); - } else { - auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0); - if (len > payload_max_length) { - exceed_payload_max_length = true; - skip_content_with_length(strm, len); - ret = false; - } else if (len > 0) { - ret = read_content_with_length(strm, len, std::move(progress), out); - } - } - - if (!ret) { - status = exceed_payload_max_length ? StatusCode::PayloadTooLarge_413 - : StatusCode::BadRequest_400; - } - return ret; - }); -} // namespace detail - -inline ssize_t write_headers(Stream &strm, const Headers &headers) { - ssize_t write_len = 0; - for (const auto &x : headers) { - auto len = - strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str()); - if (len < 0) { return len; } - write_len += len; - } - auto len = strm.write("\r\n"); - if (len < 0) { return len; } - write_len += len; - return write_len; -} - -inline bool write_data(Stream &strm, const char *d, size_t l) { - size_t offset = 0; - while (offset < l) { - auto length = strm.write(d + offset, l - offset); - if (length < 0) { return false; } - offset += static_cast(length); - } - return true; -} - -template -inline bool write_content(Stream &strm, const ContentProvider &content_provider, - size_t offset, size_t length, T is_shutting_down, - Error &error) { - size_t end_offset = offset + length; - auto ok = true; - DataSink data_sink; - - data_sink.write = [&](const char *d, size_t l) -> bool { - if (ok) { - if (strm.is_writable() && write_data(strm, d, l)) { - offset += l; - } else { - ok = false; - } - } - return ok; - }; - - data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; - - while (offset < end_offset && !is_shutting_down()) { - if (!strm.is_writable()) { - error = Error::Write; - return false; - } else if (!content_provider(offset, end_offset - offset, data_sink)) { - error = Error::Canceled; - return false; - } else if (!ok) { - error = Error::Write; - return false; - } - } - - error = Error::Success; - return true; -} - -template -inline bool write_content(Stream &strm, const ContentProvider &content_provider, - size_t offset, size_t length, - const T &is_shutting_down) { - auto error = Error::Success; - return write_content(strm, content_provider, offset, length, is_shutting_down, - error); -} - -template -inline bool -write_content_without_length(Stream &strm, - const ContentProvider &content_provider, - const T &is_shutting_down) { - size_t offset = 0; - auto data_available = true; - auto ok = true; - DataSink data_sink; - - data_sink.write = [&](const char *d, size_t l) -> bool { - if (ok) { - offset += l; - if (!strm.is_writable() || !write_data(strm, d, l)) { ok = false; } - } - return ok; - }; - - data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; - - data_sink.done = [&](void) { data_available = false; }; - - while (data_available && !is_shutting_down()) { - if (!strm.is_writable()) { - return false; - } else if (!content_provider(offset, 0, data_sink)) { - return false; - } else if (!ok) { - return false; - } - } - return true; -} - -template -inline bool -write_content_chunked(Stream &strm, const ContentProvider &content_provider, - const T &is_shutting_down, U &compressor, Error &error) { - size_t offset = 0; - auto data_available = true; - auto ok = true; - DataSink data_sink; - - data_sink.write = [&](const char *d, size_t l) -> bool { - if (ok) { - data_available = l > 0; - offset += l; - - std::string payload; - if (compressor.compress(d, l, false, - [&](const char *data, size_t data_len) { - payload.append(data, data_len); - return true; - })) { - if (!payload.empty()) { - // Emit chunked response header and footer for each chunk - auto chunk = - from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; - if (!strm.is_writable() || - !write_data(strm, chunk.data(), chunk.size())) { - ok = false; - } - } - } else { - ok = false; - } - } - return ok; - }; - - data_sink.is_writable = [&]() -> bool { return strm.is_writable(); }; - - auto done_with_trailer = [&](const Headers *trailer) { - if (!ok) { return; } - - data_available = false; - - std::string payload; - if (!compressor.compress(nullptr, 0, true, - [&](const char *data, size_t data_len) { - payload.append(data, data_len); - return true; - })) { - ok = false; - return; - } - - if (!payload.empty()) { - // Emit chunked response header and footer for each chunk - auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; - if (!strm.is_writable() || - !write_data(strm, chunk.data(), chunk.size())) { - ok = false; - return; - } - } - - static const std::string done_marker("0\r\n"); - if (!write_data(strm, done_marker.data(), done_marker.size())) { - ok = false; - } - - // Trailer - if (trailer) { - for (const auto &kv : *trailer) { - std::string field_line = kv.first + ": " + kv.second + "\r\n"; - if (!write_data(strm, field_line.data(), field_line.size())) { - ok = false; - } - } - } - - static const std::string crlf("\r\n"); - if (!write_data(strm, crlf.data(), crlf.size())) { ok = false; } - }; - - data_sink.done = [&](void) { done_with_trailer(nullptr); }; - - data_sink.done_with_trailer = [&](const Headers &trailer) { - done_with_trailer(&trailer); - }; - - while (data_available && !is_shutting_down()) { - if (!strm.is_writable()) { - error = Error::Write; - return false; - } else if (!content_provider(offset, 0, data_sink)) { - error = Error::Canceled; - return false; - } else if (!ok) { - error = Error::Write; - return false; - } - } - - error = Error::Success; - return true; -} - -template -inline bool write_content_chunked(Stream &strm, - const ContentProvider &content_provider, - const T &is_shutting_down, U &compressor) { - auto error = Error::Success; - return write_content_chunked(strm, content_provider, is_shutting_down, - compressor, error); -} - -template -inline bool redirect(T &cli, Request &req, Response &res, - const std::string &path, const std::string &location, - Error &error) { - Request new_req = req; - new_req.path = path; - new_req.redirect_count_ -= 1; - - if (res.status == StatusCode::SeeOther_303 && - (req.method != "GET" && req.method != "HEAD")) { - new_req.method = "GET"; - new_req.body.clear(); - new_req.headers.clear(); - } - - Response new_res; - - auto ret = cli.send(new_req, new_res, error); - if (ret) { - req = new_req; - res = new_res; - - if (res.location.empty()) { res.location = location; } - } return ret; } -inline std::string params_to_query_str(const Params ¶ms) { - std::string query; - - for (auto it = params.begin(); it != params.end(); ++it) { - if (it != params.begin()) { query += "&"; } - query += it->first; - query += "="; - query += encode_query_param(it->second); +template inline void write_headers(Stream &strm, const T &info) { + for (const auto &x : info.headers) { + strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str()); } - return query; + strm.write("\r\n"); +} + +template +inline void write_content_chunked(Stream &strm, const T &x) { + auto chunked_response = !x.has_header("Content-Length"); + uint64_t offset = 0; + auto data_available = true; + while (data_available) { + auto chunk = x.content_producer(offset); + offset += chunk.size(); + data_available = !chunk.empty(); + + // Emit chunked response header and footer for each chunk + if (chunked_response) { + chunk = from_i_to_hex(chunk.size()) + "\r\n" + chunk + "\r\n"; + } + + if (strm.write(chunk.c_str(), chunk.size()) < 0) { + break; // Stop on error + } + } +} + +inline std::string encode_url(const std::string &s) { + std::string result; + + for (auto i = 0; s[i]; i++) { + switch (s[i]) { + case ' ': result += "%20"; break; + case '+': result += "%2B"; break; + case '\r': result += "%0D"; break; + case '\n': result += "%0A"; break; + case '\'': result += "%27"; break; + case ',': result += "%2C"; break; + case ':': result += "%3A"; break; + case ';': result += "%3B"; break; + default: + auto c = static_cast(s[i]); + if (c >= 0x80) { + result += '%'; + char hex[4]; + size_t len = snprintf(hex, sizeof(hex) - 1, "%02X", c); + assert(len == 2); + result.append(hex, len); + } else { + result += s[i]; + } + break; + } + } + + return result; +} + +inline std::string decode_url(const std::string &s) { + std::string result; + + for (size_t i = 0; i < s.size(); i++) { + if (s[i] == '%' && i + 1 < s.size()) { + if (s[i + 1] == 'u') { + int val = 0; + if (from_hex_to_i(s, i + 2, 4, val)) { + // 4 digits Unicode codes + char buff[4]; + size_t len = to_utf8(val, buff); + if (len > 0) { result.append(buff, len); } + i += 5; // 'u0000' + } else { + result += s[i]; + } + } else { + int val = 0; + if (from_hex_to_i(s, i + 1, 2, val)) { + // 2 digits hex codes + result += val; + i += 2; // '00' + } else { + result += s[i]; + } + } + } else if (s[i] == '+') { + result += ' '; + } else { + result += s[i]; + } + } + + return result; } inline void parse_query_text(const std::string &s, Params ¶ms) { - std::set cache; - split(s.data(), s.data() + s.size(), '&', [&](const char *b, const char *e) { - std::string kv(b, e); - if (cache.find(kv) != cache.end()) { return; } - cache.insert(kv); - + split(&s[0], &s[s.size()], '&', [&](const char *b, const char *e) { std::string key; std::string val; - split(b, e, '=', [&](const char *b2, const char *e2) { + split(b, e, '=', [&](const char *b, const char *e) { if (key.empty()) { - key.assign(b2, e2); + key.assign(b, e); } else { - val.assign(b2, e2); + val.assign(b, e); } }); - - if (!key.empty()) { - params.emplace(decode_url(key, true), decode_url(val, true)); - } + params.emplace(key, decode_url(val)); }); } inline bool parse_multipart_boundary(const std::string &content_type, std::string &boundary) { - auto boundary_keyword = "boundary="; - auto pos = content_type.find(boundary_keyword); + auto pos = content_type.find("boundary="); if (pos == std::string::npos) { return false; } - auto end = content_type.find(';', pos); - auto beg = pos + strlen(boundary_keyword); - boundary = trim_double_quotes_copy(content_type.substr(beg, end - beg)); - return !boundary.empty(); + + boundary = content_type.substr(pos + 9); + return true; } -inline void parse_disposition_params(const std::string &s, Params ¶ms) { - std::set cache; - split(s.data(), s.data() + s.size(), ';', [&](const char *b, const char *e) { - std::string kv(b, e); - if (cache.find(kv) != cache.end()) { return; } - cache.insert(kv); +inline bool parse_multipart_formdata(const std::string &boundary, + const std::string &body, + MultipartFiles &files) { + static std::string dash = "--"; + static std::string crlf = "\r\n"; - std::string key; - std::string val; - split(b, e, '=', [&](const char *b2, const char *e2) { - if (key.empty()) { - key.assign(b2, e2); - } else { - val.assign(b2, e2); + static std::regex re_content_type("Content-Type: (.*?)", + std::regex_constants::icase); + + static std::regex re_content_disposition( + "Content-Disposition: form-data; name=\"(.*?)\"(?:; filename=\"(.*?)\")?", + std::regex_constants::icase); + + auto dash_boundary = dash + boundary; + + auto pos = body.find(dash_boundary); + if (pos != 0) { return false; } + + pos += dash_boundary.size(); + + auto next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + pos = next_pos + crlf.size(); + + while (pos < body.size()) { + next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + std::string name; + MultipartFile file; + + auto header = body.substr(pos, (next_pos - pos)); + + while (pos != next_pos) { + std::smatch m; + if (std::regex_match(header, m, re_content_type)) { + file.content_type = m[1]; + } else if (std::regex_match(header, m, re_content_disposition)) { + name = m[1]; + file.filename = m[2]; } - }); - if (!key.empty()) { - params.emplace(trim_double_quotes_copy((key)), - trim_double_quotes_copy((val))); + pos = next_pos + crlf.size(); + + next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + header = body.substr(pos, (next_pos - pos)); } - }); + + pos = next_pos + crlf.size(); + + next_pos = body.find(crlf + dash_boundary, pos); + + if (next_pos == std::string::npos) { return false; } + + file.offset = pos; + file.length = next_pos - pos; + + pos = next_pos + crlf.size() + dash_boundary.size(); + + next_pos = body.find(crlf, pos); + if (next_pos == std::string::npos) { return false; } + + files.emplace(name, file); + + pos = next_pos + crlf.size(); + } + + return true; } -#ifdef CPPHTTPLIB_NO_EXCEPTIONS -inline bool parse_range_header(const std::string &s, Ranges &ranges) { -#else -inline bool parse_range_header(const std::string &s, Ranges &ranges) try { -#endif - static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))"); - std::smatch m; - if (std::regex_match(s, m, re_first_range)) { - auto pos = static_cast(m.position(1)); - auto len = static_cast(m.length(1)); - auto all_valid_ranges = true; - split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) { - if (!all_valid_ranges) { return; } - static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))"); - std::cmatch cm; - if (std::regex_match(b, e, cm, re_another_range)) { - ssize_t first = -1; - if (!cm.str(1).empty()) { - first = static_cast(std::stoll(cm.str(1))); - } - - ssize_t last = -1; - if (!cm.str(2).empty()) { - last = static_cast(std::stoll(cm.str(2))); - } - - if (first != -1 && last != -1 && first > last) { - all_valid_ranges = false; - return; - } - ranges.emplace_back(std::make_pair(first, last)); - } - }); - return all_valid_ranges; - } - return false; -#ifdef CPPHTTPLIB_NO_EXCEPTIONS -} -#else -} catch (...) { return false; } -#endif - -class MultipartFormDataParser { -public: - MultipartFormDataParser() = default; - - void set_boundary(std::string &&boundary) { - boundary_ = boundary; - dash_boundary_crlf_ = dash_ + boundary_ + crlf_; - crlf_dash_boundary_ = crlf_ + dash_ + boundary_; - } - - bool is_valid() const { return is_valid_; } - - bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, - const MultipartContentHeader &header_callback) { - - buf_append(buf, n); - - while (buf_size() > 0) { - switch (state_) { - case 0: { // Initial boundary - buf_erase(buf_find(dash_boundary_crlf_)); - if (dash_boundary_crlf_.size() > buf_size()) { return true; } - if (!buf_start_with(dash_boundary_crlf_)) { return false; } - buf_erase(dash_boundary_crlf_.size()); - state_ = 1; - break; - } - case 1: { // New entry - clear_file_info(); - state_ = 2; - break; - } - case 2: { // Headers - auto pos = buf_find(crlf_); - if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } - while (pos < buf_size()) { - // Empty line - if (pos == 0) { - if (!header_callback(file_)) { - is_valid_ = false; - return false; - } - buf_erase(crlf_.size()); - state_ = 3; - break; - } - - const auto header = buf_head(pos); - - if (!parse_header(header.data(), header.data() + header.size(), - [&](std::string &&, std::string &&) {})) { - is_valid_ = false; - return false; - } - - static const std::string header_content_type = "Content-Type:"; - - if (start_with_case_ignore(header, header_content_type)) { - file_.content_type = - trim_copy(header.substr(header_content_type.size())); - } else { - static const std::regex re_content_disposition( - R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~", - std::regex_constants::icase); - - std::smatch m; - if (std::regex_match(header, m, re_content_disposition)) { - Params params; - parse_disposition_params(m[1], params); - - auto it = params.find("name"); - if (it != params.end()) { - file_.name = it->second; - } else { - is_valid_ = false; - return false; - } - - it = params.find("filename"); - if (it != params.end()) { file_.filename = it->second; } - - it = params.find("filename*"); - if (it != params.end()) { - // Only allow UTF-8 enconnding... - static const std::regex re_rfc5987_encoding( - R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase); - - std::smatch m2; - if (std::regex_match(it->second, m2, re_rfc5987_encoding)) { - file_.filename = decode_url(m2[1], false); // override... - } else { - is_valid_ = false; - return false; - } - } - } - } - buf_erase(pos + crlf_.size()); - pos = buf_find(crlf_); - } - if (state_ != 3) { return true; } - break; - } - case 3: { // Body - if (crlf_dash_boundary_.size() > buf_size()) { return true; } - auto pos = buf_find(crlf_dash_boundary_); - if (pos < buf_size()) { - if (!content_callback(buf_data(), pos)) { - is_valid_ = false; - return false; - } - buf_erase(pos + crlf_dash_boundary_.size()); - state_ = 4; - } else { - auto len = buf_size() - crlf_dash_boundary_.size(); - if (len > 0) { - if (!content_callback(buf_data(), len)) { - is_valid_ = false; - return false; - } - buf_erase(len); - } - return true; - } - break; - } - case 4: { // Boundary - if (crlf_.size() > buf_size()) { return true; } - if (buf_start_with(crlf_)) { - buf_erase(crlf_.size()); - state_ = 1; - } else { - if (dash_.size() > buf_size()) { return true; } - if (buf_start_with(dash_)) { - buf_erase(dash_.size()); - is_valid_ = true; - buf_erase(buf_size()); // Remove epilogue - } else { - return true; - } - } - break; - } - } - } - - return true; - } - -private: - void clear_file_info() { - file_.name.clear(); - file_.filename.clear(); - file_.content_type.clear(); - } - - bool start_with_case_ignore(const std::string &a, - const std::string &b) const { - if (a.size() < b.size()) { return false; } - for (size_t i = 0; i < b.size(); i++) { - if (::tolower(a[i]) != ::tolower(b[i])) { return false; } - } - return true; - } - - const std::string dash_ = "--"; - const std::string crlf_ = "\r\n"; - std::string boundary_; - std::string dash_boundary_crlf_; - std::string crlf_dash_boundary_; - - size_t state_ = 0; - bool is_valid_ = false; - MultipartFormData file_; - - // Buffer - bool start_with(const std::string &a, size_t spos, size_t epos, - const std::string &b) const { - if (epos - spos < b.size()) { return false; } - for (size_t i = 0; i < b.size(); i++) { - if (a[i + spos] != b[i]) { return false; } - } - return true; - } - - size_t buf_size() const { return buf_epos_ - buf_spos_; } - - const char *buf_data() const { return &buf_[buf_spos_]; } - - std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); } - - bool buf_start_with(const std::string &s) const { - return start_with(buf_, buf_spos_, buf_epos_, s); - } - - size_t buf_find(const std::string &s) const { - auto c = s.front(); - - size_t off = buf_spos_; - while (off < buf_epos_) { - auto pos = off; - while (true) { - if (pos == buf_epos_) { return buf_size(); } - if (buf_[pos] == c) { break; } - pos++; - } - - auto remaining_size = buf_epos_ - pos; - if (s.size() > remaining_size) { return buf_size(); } - - if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; } - - off = pos + 1; - } - - return buf_size(); - } - - void buf_append(const char *data, size_t n) { - auto remaining_size = buf_size(); - if (remaining_size > 0 && buf_spos_ > 0) { - for (size_t i = 0; i < remaining_size; i++) { - buf_[i] = buf_[buf_spos_ + i]; - } - } - buf_spos_ = 0; - buf_epos_ = remaining_size; - - if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); } - - for (size_t i = 0; i < n; i++) { - buf_[buf_epos_ + i] = data[i]; - } - buf_epos_ += n; - } - - void buf_erase(size_t size) { buf_spos_ += size; } - - std::string buf_; - size_t buf_spos_ = 0; - size_t buf_epos_ = 0; -}; - inline std::string to_lower(const char *beg, const char *end) { std::string out; auto it = beg; while (it != end) { - out += static_cast(::tolower(*it)); + out += ::tolower(*it); it++; } return out; } -inline std::string random_string(size_t length) { - static const char data[] = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +inline void make_range_header_core(std::string &) {} - // std::random_device might actually be deterministic on some - // platforms, but due to lack of support in the c++ standard library, - // doing better requires either some ugly hacks or breaking portability. - static std::random_device seed_gen; - - // Request 128 bits of entropy for initialization - static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), - seed_gen()}; - - static std::mt19937 engine(seed_sequence); - - std::string result; - for (size_t i = 0; i < length; i++) { - result += data[engine() % (sizeof(data) - 1)]; - } - return result; +template +inline void make_range_header_core(std::string &field, uint64_t value) { + if (!field.empty()) { field += ", "; } + field += std::to_string(value) + "-"; } -inline std::string make_multipart_data_boundary() { - return "--cpp-httplib-multipart-data-" + detail::random_string(16); +template +inline void make_range_header_core(std::string &field, uint64_t value1, + uint64_t value2, Args... args) { + if (!field.empty()) { field += ", "; } + field += std::to_string(value1) + "-" + std::to_string(value2); + make_range_header_core(field, args...); } -inline bool is_multipart_boundary_chars_valid(const std::string &boundary) { - auto valid = true; - for (size_t i = 0; i < boundary.size(); i++) { - auto c = boundary[i]; - if (!std::isalnum(c) && c != '-' && c != '_') { - valid = false; - break; - } - } - return valid; -} - -template -inline std::string -serialize_multipart_formdata_item_begin(const T &item, - const std::string &boundary) { - std::string body = "--" + boundary + "\r\n"; - body += "Content-Disposition: form-data; name=\"" + item.name + "\""; - if (!item.filename.empty()) { - body += "; filename=\"" + item.filename + "\""; - } - body += "\r\n"; - if (!item.content_type.empty()) { - body += "Content-Type: " + item.content_type + "\r\n"; - } - body += "\r\n"; - - return body; -} - -inline std::string serialize_multipart_formdata_item_end() { return "\r\n"; } - -inline std::string -serialize_multipart_formdata_finish(const std::string &boundary) { - return "--" + boundary + "--\r\n"; -} - -inline std::string -serialize_multipart_formdata_get_content_type(const std::string &boundary) { - return "multipart/form-data; boundary=" + boundary; -} - -inline std::string -serialize_multipart_formdata(const MultipartFormDataItems &items, - const std::string &boundary, bool finish = true) { - std::string body; - - for (const auto &item : items) { - body += serialize_multipart_formdata_item_begin(item, boundary); - body += item.content + serialize_multipart_formdata_item_end(); - } - - if (finish) { body += serialize_multipart_formdata_finish(boundary); } - - return body; -} - -inline bool range_error(Request &req, Response &res) { - if (!req.ranges.empty() && 200 <= res.status && res.status < 300) { - ssize_t contant_len = static_cast( - res.content_length_ ? res.content_length_ : res.body.size()); - - ssize_t prev_first_pos = -1; - ssize_t prev_last_pos = -1; - size_t overwrapping_count = 0; - - // NOTE: The following Range check is based on '14.2. Range' in RFC 9110 - // 'HTTP Semantics' to avoid potential denial-of-service attacks. - // https://www.rfc-editor.org/rfc/rfc9110#section-14.2 - - // Too many ranges - if (req.ranges.size() > CPPHTTPLIB_RANGE_MAX_COUNT) { return true; } - - for (auto &r : req.ranges) { - auto &first_pos = r.first; - auto &last_pos = r.second; - - if (first_pos == -1 && last_pos == -1) { - first_pos = 0; - last_pos = contant_len; - } - - if (first_pos == -1) { - first_pos = contant_len - last_pos; - last_pos = contant_len - 1; - } - - if (last_pos == -1) { last_pos = contant_len - 1; } - - // Range must be within content length - if (!(0 <= first_pos && first_pos <= last_pos && - last_pos <= contant_len - 1)) { - return true; - } - - // Ranges must be in ascending order - if (first_pos <= prev_first_pos) { return true; } - - // Request must not have more than two overlapping ranges - if (first_pos <= prev_last_pos) { - overwrapping_count++; - if (overwrapping_count > 2) { return true; } - } - - prev_first_pos = (std::max)(prev_first_pos, first_pos); - prev_last_pos = (std::max)(prev_last_pos, last_pos); - } - } - - return false; -} - -inline std::pair -get_range_offset_and_length(Range r, size_t content_length) { - assert(r.first != -1 && r.second != -1); - assert(0 <= r.first && r.first < static_cast(content_length)); - assert(r.first <= r.second && - r.second < static_cast(content_length)); - - return std::make_pair(r.first, static_cast(r.second - r.first) + 1); -} - -inline std::string make_content_range_header_field( - const std::pair &offset_and_length, size_t content_length) { - auto st = offset_and_length.first; - auto ed = st + offset_and_length.second - 1; - - std::string field = "bytes "; - field += std::to_string(st); - field += "-"; - field += std::to_string(ed); - field += "/"; - field += std::to_string(content_length); - return field; -} - -template -bool process_multipart_ranges_data(const Request &req, - const std::string &boundary, - const std::string &content_type, - size_t content_length, SToken stoken, - CToken ctoken, Content content) { - for (size_t i = 0; i < req.ranges.size(); i++) { - ctoken("--"); - stoken(boundary); - ctoken("\r\n"); - if (!content_type.empty()) { - ctoken("Content-Type: "); - stoken(content_type); - ctoken("\r\n"); - } - - auto offset_and_length = - get_range_offset_and_length(req.ranges[i], content_length); - - ctoken("Content-Range: "); - stoken(make_content_range_header_field(offset_and_length, content_length)); - ctoken("\r\n"); - ctoken("\r\n"); - - if (!content(offset_and_length.first, offset_and_length.second)) { - return false; - } - ctoken("\r\n"); - } - - ctoken("--"); - stoken(boundary); - ctoken("--"); - - return true; -} - -inline void make_multipart_ranges_data(const Request &req, Response &res, - const std::string &boundary, - const std::string &content_type, - size_t content_length, - std::string &data) { - process_multipart_ranges_data( - req, boundary, content_type, content_length, - [&](const std::string &token) { data += token; }, - [&](const std::string &token) { data += token; }, - [&](size_t offset, size_t length) { - assert(offset + length <= content_length); - data += res.body.substr(offset, length); - return true; - }); -} - -inline size_t get_multipart_ranges_data_length(const Request &req, - const std::string &boundary, - const std::string &content_type, - size_t content_length) { - size_t data_length = 0; - - process_multipart_ranges_data( - req, boundary, content_type, content_length, - [&](const std::string &token) { data_length += token.size(); }, - [&](const std::string &token) { data_length += token.size(); }, - [&](size_t /*offset*/, size_t length) { - data_length += length; - return true; - }); - - return data_length; -} - -template -inline bool -write_multipart_ranges_data(Stream &strm, const Request &req, Response &res, - const std::string &boundary, - const std::string &content_type, - size_t content_length, const T &is_shutting_down) { - return process_multipart_ranges_data( - req, boundary, content_type, content_length, - [&](const std::string &token) { strm.write(token); }, - [&](const std::string &token) { strm.write(token); }, - [&](size_t offset, size_t length) { - return write_content(strm, res.content_provider_, offset, length, - is_shutting_down); - }); -} - -inline bool expect_content(const Request &req) { - if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" || - req.method == "PRI" || req.method == "DELETE") { - return true; - } - // TODO: check if Content-Length is set - return false; -} - -inline bool has_crlf(const std::string &s) { - auto p = s.c_str(); - while (*p) { - if (*p == '\r' || *p == '\n') { return true; } - p++; - } - return false; -} - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline std::string message_digest(const std::string &s, const EVP_MD *algo) { - auto context = std::unique_ptr( - EVP_MD_CTX_new(), EVP_MD_CTX_free); - - unsigned int hash_length = 0; - unsigned char hash[EVP_MAX_MD_SIZE]; - - EVP_DigestInit_ex(context.get(), algo, nullptr); - EVP_DigestUpdate(context.get(), s.c_str(), s.size()); - EVP_DigestFinal_ex(context.get(), hash, &hash_length); - - std::stringstream ss; - for (auto i = 0u; i < hash_length; ++i) { - ss << std::hex << std::setw(2) << std::setfill('0') - << static_cast(hash[i]); - } - - return ss.str(); -} - -inline std::string MD5(const std::string &s) { - return message_digest(s, EVP_md5()); -} - -inline std::string SHA_256(const std::string &s) { - return message_digest(s, EVP_sha256()); -} - -inline std::string SHA_512(const std::string &s) { - return message_digest(s, EVP_sha512()); -} -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -#ifdef _WIN32 -// NOTE: This code came up with the following stackoverflow post: -// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store -inline bool load_system_certs_on_windows(X509_STORE *store) { - auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT"); - if (!hStore) { return false; } - - auto result = false; - PCCERT_CONTEXT pContext = NULL; - while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != - nullptr) { - auto encoded_cert = - static_cast(pContext->pbCertEncoded); - - auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); - if (x509) { - X509_STORE_add_cert(store, x509); - X509_free(x509); - result = true; - } - } - - CertFreeCertificateContext(pContext); - CertCloseStore(hStore, 0); - - return result; -} -#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) -#if TARGET_OS_OSX -template -using CFObjectPtr = - std::unique_ptr::type, void (*)(CFTypeRef)>; - -inline void cf_object_ptr_deleter(CFTypeRef obj) { - if (obj) { CFRelease(obj); } -} - -inline bool retrieve_certs_from_keychain(CFObjectPtr &certs) { - CFStringRef keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef}; - CFTypeRef values[] = {kSecClassCertificate, kSecMatchLimitAll, - kCFBooleanTrue}; - - CFObjectPtr query( - CFDictionaryCreate(nullptr, reinterpret_cast(keys), values, - sizeof(keys) / sizeof(keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks), - cf_object_ptr_deleter); - - if (!query) { return false; } - - CFTypeRef security_items = nullptr; - if (SecItemCopyMatching(query.get(), &security_items) != errSecSuccess || - CFArrayGetTypeID() != CFGetTypeID(security_items)) { - return false; - } - - certs.reset(reinterpret_cast(security_items)); - return true; -} - -inline bool retrieve_root_certs_from_keychain(CFObjectPtr &certs) { - CFArrayRef root_security_items = nullptr; - if (SecTrustCopyAnchorCertificates(&root_security_items) != errSecSuccess) { - return false; - } - - certs.reset(root_security_items); - return true; -} - -inline bool add_certs_to_x509_store(CFArrayRef certs, X509_STORE *store) { - auto result = false; - for (auto i = 0; i < CFArrayGetCount(certs); ++i) { - const auto cert = reinterpret_cast( - CFArrayGetValueAtIndex(certs, i)); - - if (SecCertificateGetTypeID() != CFGetTypeID(cert)) { continue; } - - CFDataRef cert_data = nullptr; - if (SecItemExport(cert, kSecFormatX509Cert, 0, nullptr, &cert_data) != - errSecSuccess) { - continue; - } - - CFObjectPtr cert_data_ptr(cert_data, cf_object_ptr_deleter); - - auto encoded_cert = static_cast( - CFDataGetBytePtr(cert_data_ptr.get())); - - auto x509 = - d2i_X509(NULL, &encoded_cert, CFDataGetLength(cert_data_ptr.get())); - - if (x509) { - X509_STORE_add_cert(store, x509); - X509_free(x509); - result = true; - } - } - - return result; -} - -inline bool load_system_certs_on_macos(X509_STORE *store) { - auto result = false; - CFObjectPtr certs(nullptr, cf_object_ptr_deleter); - if (retrieve_certs_from_keychain(certs) && certs) { - result = add_certs_to_x509_store(certs.get(), store); - } - - if (retrieve_root_certs_from_keychain(certs) && certs) { - result = add_certs_to_x509_store(certs.get(), store) || result; - } - - return result; -} -#endif // TARGET_OS_OSX -#endif // _WIN32 -#endif // CPPHTTPLIB_OPENSSL_SUPPORT - #ifdef _WIN32 class WSInit { public: WSInit() { WSADATA wsaData; - if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true; + WSAStartup(0x0002, &wsaData); } - ~WSInit() { - if (is_valid_) WSACleanup(); - } - - bool is_valid_ = false; + ~WSInit() { WSACleanup(); } }; static WSInit wsinit_; #endif -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline std::pair make_digest_authentication_header( - const Request &req, const std::map &auth, - size_t cnonce_count, const std::string &cnonce, const std::string &username, - const std::string &password, bool is_proxy = false) { - std::string nc; - { - std::stringstream ss; - ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count; - nc = ss.str(); - } - - std::string qop; - if (auth.find("qop") != auth.end()) { - qop = auth.at("qop"); - if (qop.find("auth-int") != std::string::npos) { - qop = "auth-int"; - } else if (qop.find("auth") != std::string::npos) { - qop = "auth"; - } else { - qop.clear(); - } - } - - std::string algo = "MD5"; - if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); } - - std::string response; - { - auto H = algo == "SHA-256" ? detail::SHA_256 - : algo == "SHA-512" ? detail::SHA_512 - : detail::MD5; - - auto A1 = username + ":" + auth.at("realm") + ":" + password; - - auto A2 = req.method + ":" + req.path; - if (qop == "auth-int") { A2 += ":" + H(req.body); } - - if (qop.empty()) { - response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2)); - } else { - response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce + - ":" + qop + ":" + H(A2)); - } - } - - auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : ""; - - auto field = "Digest username=\"" + username + "\", realm=\"" + - auth.at("realm") + "\", nonce=\"" + auth.at("nonce") + - "\", uri=\"" + req.path + "\", algorithm=" + algo + - (qop.empty() ? ", response=\"" - : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" + - cnonce + "\", response=\"") + - response + "\"" + - (opaque.empty() ? "" : ", opaque=\"" + opaque + "\""); - - auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; - return std::make_pair(key, field); -} -#endif - -inline bool parse_www_authenticate(const Response &res, - std::map &auth, - bool is_proxy) { - auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate"; - if (res.has_header(auth_key)) { - static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~"); - auto s = res.get_header_value(auth_key); - auto pos = s.find(' '); - if (pos != std::string::npos) { - auto type = s.substr(0, pos); - if (type == "Basic") { - return false; - } else if (type == "Digest") { - s = s.substr(pos + 1); - auto beg = std::sregex_iterator(s.begin(), s.end(), re); - for (auto i = beg; i != std::sregex_iterator(); ++i) { - const auto &m = *i; - auto key = s.substr(static_cast(m.position(1)), - static_cast(m.length(1))); - auto val = m.length(2) > 0 - ? s.substr(static_cast(m.position(2)), - static_cast(m.length(2))) - : s.substr(static_cast(m.position(3)), - static_cast(m.length(3))); - auth[key] = val; - } - return true; - } - } - } - return false; -} - -class ContentProviderAdapter { -public: - explicit ContentProviderAdapter( - ContentProviderWithoutLength &&content_provider) - : content_provider_(content_provider) {} - - bool operator()(size_t offset, size_t, DataSink &sink) { - return content_provider_(offset, sink); - } - -private: - ContentProviderWithoutLength content_provider_; -}; - } // namespace detail -inline std::string hosted_at(const std::string &hostname) { - std::vector addrs; - hosted_at(hostname, addrs); - if (addrs.empty()) { return std::string(); } - return addrs[0]; -} - -inline void hosted_at(const std::string &hostname, - std::vector &addrs) { - struct addrinfo hints; - struct addrinfo *result; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) { -#if defined __linux__ && !defined __ANDROID__ - res_init(); -#endif - return; - } - - for (auto rp = result; rp; rp = rp->ai_next) { - const auto &addr = - *reinterpret_cast(rp->ai_addr); - std::string ip; - auto dummy = -1; - if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage), ip, - dummy)) { - addrs.push_back(ip); - } - } - - freeaddrinfo(result); -} - -inline std::string append_query_params(const std::string &path, - const Params ¶ms) { - std::string path_with_query = path; - const static std::regex re("[^?]+\\?.*"); - auto delm = std::regex_match(path, re) ? '&' : '?'; - path_with_query += delm + detail::params_to_query_str(params); - return path_with_query; -} - // Header utilities -inline std::pair -make_range_header(const Ranges &ranges) { - std::string field = "bytes="; - auto i = 0; - for (const auto &r : ranges) { - if (i != 0) { field += ", "; } - if (r.first != -1) { field += std::to_string(r.first); } - field += '-'; - if (r.second != -1) { field += std::to_string(r.second); } - i++; - } - return std::make_pair("Range", std::move(field)); +template +inline std::pair make_range_header(uint64_t value, + Args... args) { + std::string field; + detail::make_range_header_core(field, value, args...); + field.insert(0, "bytes="); + return std::make_pair("Range", field); } -inline std::pair -make_basic_authentication_header(const std::string &username, - const std::string &password, bool is_proxy) { + +inline std::pair +make_basic_authentication_header(const std::string& username, const std::string& password) { auto field = "Basic " + detail::base64_encode(username + ":" + password); - auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; - return std::make_pair(key, std::move(field)); + return std::make_pair("Authorization", field); } - -inline std::pair -make_bearer_token_authentication_header(const std::string &token, - bool is_proxy = false) { - auto field = "Bearer " + token; - auto key = is_proxy ? "Proxy-Authorization" : "Authorization"; - return std::make_pair(key, std::move(field)); -} - // Request implementation -inline bool Request::has_header(const std::string &key) const { +inline bool Request::has_header(const char *key) const { return detail::has_header(headers, key); } -inline std::string Request::get_header_value(const std::string &key, - size_t id) const { +inline std::string Request::get_header_value(const char *key, size_t id) const { return detail::get_header_value(headers, key, id, ""); } -inline size_t Request::get_header_value_count(const std::string &key) const { +inline size_t Request::get_header_value_count(const char *key) const { auto r = headers.equal_range(key); - return static_cast(std::distance(r.first, r.second)); + return std::distance(r.first, r.second); } -inline void Request::set_header(const std::string &key, - const std::string &val) { - if (!detail::has_crlf(key) && !detail::has_crlf(val)) { - headers.emplace(key, val); - } +inline void Request::set_header(const char *key, const char *val) { + headers.emplace(key, val); } -inline bool Request::has_param(const std::string &key) const { +inline bool Request::has_param(const char *key) const { return params.find(key) != params.end(); } -inline std::string Request::get_param_value(const std::string &key, - size_t id) const { - auto rng = params.equal_range(key); - auto it = rng.first; - std::advance(it, static_cast(id)); - if (it != rng.second) { return it->second; } +inline std::string Request::get_param_value(const char *key, size_t id) const { + auto it = params.find(key); + std::advance(it, id); + if (it != params.end()) { return it->second; } return std::string(); } -inline size_t Request::get_param_value_count(const std::string &key) const { +inline size_t Request::get_param_value_count(const char *key) const { auto r = params.equal_range(key); - return static_cast(std::distance(r.first, r.second)); + return std::distance(r.first, r.second); } -inline bool Request::is_multipart_form_data() const { - const auto &content_type = get_header_value("Content-Type"); - return !content_type.rfind("multipart/form-data", 0); -} - -inline bool Request::has_file(const std::string &key) const { +inline bool Request::has_file(const char *key) const { return files.find(key) != files.end(); } -inline MultipartFormData Request::get_file_value(const std::string &key) const { +inline MultipartFile Request::get_file_value(const char *key) const { auto it = files.find(key); if (it != files.end()) { return it->second; } - return MultipartFormData(); -} - -inline std::vector -Request::get_file_values(const std::string &key) const { - std::vector values; - auto rng = files.equal_range(key); - for (auto it = rng.first; it != rng.second; it++) { - values.push_back(it->second); - } - return values; + return MultipartFile(); } // Response implementation -inline bool Response::has_header(const std::string &key) const { +inline bool Response::has_header(const char *key) const { return headers.find(key) != headers.end(); } -inline std::string Response::get_header_value(const std::string &key, +inline std::string Response::get_header_value(const char *key, size_t id) const { return detail::get_header_value(headers, key, id, ""); } -inline size_t Response::get_header_value_count(const std::string &key) const { +inline size_t Response::get_header_value_count(const char *key) const { auto r = headers.equal_range(key); - return static_cast(std::distance(r.first, r.second)); + return std::distance(r.first, r.second); } -inline void Response::set_header(const std::string &key, - const std::string &val) { - if (!detail::has_crlf(key) && !detail::has_crlf(val)) { - headers.emplace(key, val); - } +inline void Response::set_header(const char *key, const char *val) { + headers.emplace(key, val); } -inline void Response::set_redirect(const std::string &url, int stat) { - if (!detail::has_crlf(url)) { - set_header("Location", url); - if (300 <= stat && stat < 400) { - this->status = stat; - } else { - this->status = StatusCode::Found_302; - } - } +inline void Response::set_redirect(const char *url) { + set_header("Location", url); + status = 302; } inline void Response::set_content(const char *s, size_t n, - const std::string &content_type) { + const char *content_type) { body.assign(s, n); - - auto rng = headers.equal_range("Content-Type"); - headers.erase(rng.first, rng.second); set_header("Content-Type", content_type); } inline void Response::set_content(const std::string &s, - const std::string &content_type) { - set_content(s.data(), s.size(), content_type); -} - -inline void Response::set_content(std::string &&s, - const std::string &content_type) { - body = std::move(s); - - auto rng = headers.equal_range("Content-Type"); - headers.erase(rng.first, rng.second); + const char *content_type) { + body = s; set_header("Content-Type", content_type); } -inline void Response::set_content_provider( - size_t in_length, const std::string &content_type, ContentProvider provider, - ContentProviderResourceReleaser resource_releaser) { - set_header("Content-Type", content_type); - content_length_ = in_length; - if (in_length > 0) { content_provider_ = std::move(provider); } - content_provider_resource_releaser_ = std::move(resource_releaser); - is_chunked_content_provider_ = false; +// Rstream implementation +template +inline void Stream::write_format(const char *fmt, const Args &... args) { + const auto bufsiz = 2048; + char buf[bufsiz]; + +#if defined(_MSC_VER) && _MSC_VER < 1900 + auto n = _snprintf_s(buf, bufsiz, bufsiz - 1, fmt, args...); +#else + auto n = snprintf(buf, bufsiz - 1, fmt, args...); +#endif + if (n > 0) { + if (n >= bufsiz - 1) { + std::vector glowable_buf(bufsiz); + + while (n >= static_cast(glowable_buf.size() - 1)) { + glowable_buf.resize(glowable_buf.size() * 2); +#if defined(_MSC_VER) && _MSC_VER < 1900 + n = _snprintf_s(&glowable_buf[0], glowable_buf.size(), + glowable_buf.size() - 1, fmt, args...); +#else + n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...); +#endif + } + write(&glowable_buf[0], n); + } else { + write(buf, n); + } + } } -inline void Response::set_content_provider( - const std::string &content_type, ContentProviderWithoutLength provider, - ContentProviderResourceReleaser resource_releaser) { - set_header("Content-Type", content_type); - content_length_ = 0; - content_provider_ = detail::ContentProviderAdapter(std::move(provider)); - content_provider_resource_releaser_ = std::move(resource_releaser); - is_chunked_content_provider_ = false; +// Socket stream implementation +inline SocketStream::SocketStream(socket_t sock) : sock_(sock) {} + +inline SocketStream::~SocketStream() {} + +inline int SocketStream::read(char *ptr, size_t size) { + if (detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND, + CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) { + return recv(sock_, ptr, static_cast(size), 0); + } + return -1; } -inline void Response::set_chunked_content_provider( - const std::string &content_type, ContentProviderWithoutLength provider, - ContentProviderResourceReleaser resource_releaser) { - set_header("Content-Type", content_type); - content_length_ = 0; - content_provider_ = detail::ContentProviderAdapter(std::move(provider)); - content_provider_resource_releaser_ = std::move(resource_releaser); - is_chunked_content_provider_ = true; +inline int SocketStream::write(const char *ptr, size_t size) { + return send(sock_, ptr, static_cast(size), 0); } -// Result implementation -inline bool Result::has_request_header(const std::string &key) const { - return request_headers_.find(key) != request_headers_.end(); -} - -inline std::string Result::get_request_header_value(const std::string &key, - size_t id) const { - return detail::get_header_value(request_headers_, key, id, ""); -} - -inline size_t -Result::get_request_header_value_count(const std::string &key) const { - auto r = request_headers_.equal_range(key); - return static_cast(std::distance(r.first, r.second)); -} - -// Stream implementation -inline ssize_t Stream::write(const char *ptr) { +inline int SocketStream::write(const char *ptr) { return write(ptr, strlen(ptr)); } -inline ssize_t Stream::write(const std::string &s) { - return write(s.data(), s.size()); +inline std::string SocketStream::get_remote_addr() const { + return detail::get_remote_addr(sock_); } -namespace detail { - -// Socket stream implementation -inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec, - time_t read_timeout_usec, - time_t write_timeout_sec, - time_t write_timeout_usec) - : sock_(sock), read_timeout_sec_(read_timeout_sec), - read_timeout_usec_(read_timeout_usec), - write_timeout_sec_(write_timeout_sec), - write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {} - -inline SocketStream::~SocketStream() = default; - -inline bool SocketStream::is_readable() const { - return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; -} - -inline bool SocketStream::is_writable() const { - return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 && - is_socket_alive(sock_); -} - -inline ssize_t SocketStream::read(char *ptr, size_t size) { -#ifdef _WIN32 - size = - (std::min)(size, static_cast((std::numeric_limits::max)())); -#else - size = (std::min)(size, - static_cast((std::numeric_limits::max)())); -#endif - - if (read_buff_off_ < read_buff_content_size_) { - auto remaining_size = read_buff_content_size_ - read_buff_off_; - if (size <= remaining_size) { - memcpy(ptr, read_buff_.data() + read_buff_off_, size); - read_buff_off_ += size; - return static_cast(size); - } else { - memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size); - read_buff_off_ += remaining_size; - return static_cast(remaining_size); - } - } - - if (!is_readable()) { return -1; } - - read_buff_off_ = 0; - read_buff_content_size_ = 0; - - if (size < read_buff_size_) { - auto n = read_socket(sock_, read_buff_.data(), read_buff_size_, - CPPHTTPLIB_RECV_FLAGS); - if (n <= 0) { - return n; - } else if (n <= static_cast(size)) { - memcpy(ptr, read_buff_.data(), static_cast(n)); - return n; - } else { - memcpy(ptr, read_buff_.data(), size); - read_buff_off_ = size; - read_buff_content_size_ = static_cast(n); - return static_cast(size); - } - } else { - return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS); - } -} - -inline ssize_t SocketStream::write(const char *ptr, size_t size) { - if (!is_writable()) { return -1; } - -#if defined(_WIN32) && !defined(_WIN64) - size = - (std::min)(size, static_cast((std::numeric_limits::max)())); -#endif - - return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS); -} - -inline void SocketStream::get_remote_ip_and_port(std::string &ip, - int &port) const { - return detail::get_remote_ip_and_port(sock_, ip, port); -} - -inline void SocketStream::get_local_ip_and_port(std::string &ip, - int &port) const { - return detail::get_local_ip_and_port(sock_, ip, port); -} - -inline socket_t SocketStream::socket() const { return sock_; } - // Buffer stream implementation -inline bool BufferStream::is_readable() const { return true; } - -inline bool BufferStream::is_writable() const { return true; } - -inline ssize_t BufferStream::read(char *ptr, size_t size) { -#if defined(_MSC_VER) && _MSC_VER < 1910 - auto len_read = buffer._Copy_s(ptr, size, size, position); +inline int BufferStream::read(char *ptr, size_t size) { +#if defined(_MSC_VER) && _MSC_VER < 1900 + return static_cast(buffer._Copy_s(ptr, size, size)); #else - auto len_read = buffer.copy(ptr, size, position); + return static_cast(buffer.copy(ptr, size)); #endif - position += static_cast(len_read); - return static_cast(len_read); } -inline ssize_t BufferStream::write(const char *ptr, size_t size) { +inline int BufferStream::write(const char *ptr, size_t size) { buffer.append(ptr, size); - return static_cast(size); + return static_cast(size); } -inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/, - int & /*port*/) const {} +inline int BufferStream::write(const char *ptr) { + size_t size = strlen(ptr); + buffer.append(ptr, size); + return static_cast(size); +} -inline void BufferStream::get_local_ip_and_port(std::string & /*ip*/, - int & /*port*/) const {} - -inline socket_t BufferStream::socket() const { return 0; } +inline std::string BufferStream::get_remote_addr() const { return ""; } inline const std::string &BufferStream::get_buffer() const { return buffer; } -inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) { - // One past the last ending position of a path param substring - std::size_t last_param_end = 0; - -#ifndef CPPHTTPLIB_NO_EXCEPTIONS - // Needed to ensure that parameter names are unique during matcher - // construction - // If exceptions are disabled, only last duplicate path - // parameter will be set - std::unordered_set param_name_set; -#endif - - while (true) { - const auto marker_pos = pattern.find(marker, last_param_end); - if (marker_pos == std::string::npos) { break; } - - static_fragments_.push_back( - pattern.substr(last_param_end, marker_pos - last_param_end)); - - const auto param_name_start = marker_pos + 1; - - auto sep_pos = pattern.find(separator, param_name_start); - if (sep_pos == std::string::npos) { sep_pos = pattern.length(); } - - auto param_name = - pattern.substr(param_name_start, sep_pos - param_name_start); - -#ifndef CPPHTTPLIB_NO_EXCEPTIONS - if (param_name_set.find(param_name) != param_name_set.cend()) { - std::string msg = "Encountered path parameter '" + param_name + - "' multiple times in route pattern '" + pattern + "'."; - throw std::invalid_argument(msg); - } -#endif - - param_names_.push_back(std::move(param_name)); - - last_param_end = sep_pos + 1; - } - - if (last_param_end < pattern.length()) { - static_fragments_.push_back(pattern.substr(last_param_end)); - } -} - -inline bool PathParamsMatcher::match(Request &request) const { - request.matches = std::smatch(); - request.path_params.clear(); - request.path_params.reserve(param_names_.size()); - - // One past the position at which the path matched the pattern last time - std::size_t starting_pos = 0; - for (size_t i = 0; i < static_fragments_.size(); ++i) { - const auto &fragment = static_fragments_[i]; - - if (starting_pos + fragment.length() > request.path.length()) { - return false; - } - - // Avoid unnecessary allocation by using strncmp instead of substr + - // comparison - if (std::strncmp(request.path.c_str() + starting_pos, fragment.c_str(), - fragment.length()) != 0) { - return false; - } - - starting_pos += fragment.length(); - - // Should only happen when we have a static fragment after a param - // Example: '/users/:id/subscriptions' - // The 'subscriptions' fragment here does not have a corresponding param - if (i >= param_names_.size()) { continue; } - - auto sep_pos = request.path.find(separator, starting_pos); - if (sep_pos == std::string::npos) { sep_pos = request.path.length(); } - - const auto ¶m_name = param_names_[i]; - - request.path_params.emplace( - param_name, request.path.substr(starting_pos, sep_pos - starting_pos)); - - // Mark everythin up to '/' as matched - starting_pos = sep_pos + 1; - } - // Returns false if the path is longer than the pattern - return starting_pos >= request.path.length(); -} - -inline bool RegexMatcher::match(Request &request) const { - request.path_params.clear(); - return std::regex_match(request.path, request.matches, regex_); -} - -} // namespace detail - // HTTP server implementation inline Server::Server() - : new_task_queue( - [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }) { + : keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT), + payload_max_length_(CPPHTTPLIB_PAYLOAD_MAX_LENGTH), is_running_(false), + svr_sock_(INVALID_SOCKET), running_threads_(0) { #ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif } -inline Server::~Server() = default; +inline Server::~Server() {} -inline std::unique_ptr -Server::make_matcher(const std::string &pattern) { - if (pattern.find("/:") != std::string::npos) { - return detail::make_unique(pattern); - } else { - return detail::make_unique(pattern); - } -} - -inline Server &Server::Get(const std::string &pattern, Handler handler) { - get_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); +inline Server &Server::Get(const char *pattern, Handler handler) { + get_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server &Server::Post(const std::string &pattern, Handler handler) { - post_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); +inline Server &Server::Post(const char *pattern, Handler handler) { + post_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server &Server::Post(const std::string &pattern, - HandlerWithContentReader handler) { - post_handlers_for_content_reader_.emplace_back(make_matcher(pattern), - std::move(handler)); +inline Server &Server::Put(const char *pattern, Handler handler) { + put_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server &Server::Put(const std::string &pattern, Handler handler) { - put_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); +inline Server &Server::Patch(const char *pattern, Handler handler) { + patch_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server &Server::Put(const std::string &pattern, - HandlerWithContentReader handler) { - put_handlers_for_content_reader_.emplace_back(make_matcher(pattern), - std::move(handler)); +inline Server &Server::Delete(const char *pattern, Handler handler) { + delete_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server &Server::Patch(const std::string &pattern, Handler handler) { - patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); +inline Server &Server::Options(const char *pattern, Handler handler) { + options_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server &Server::Patch(const std::string &pattern, - HandlerWithContentReader handler) { - patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern), - std::move(handler)); - return *this; -} - -inline Server &Server::Delete(const std::string &pattern, Handler handler) { - delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); - return *this; -} - -inline Server &Server::Delete(const std::string &pattern, - HandlerWithContentReader handler) { - delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern), - std::move(handler)); - return *this; -} - -inline Server &Server::Options(const std::string &pattern, Handler handler) { - options_handlers_.emplace_back(make_matcher(pattern), std::move(handler)); - return *this; -} - -inline bool Server::set_base_dir(const std::string &dir, - const std::string &mount_point) { - return set_mount_point(mount_point, dir); -} - -inline bool Server::set_mount_point(const std::string &mount_point, - const std::string &dir, Headers headers) { - if (detail::is_dir(dir)) { - std::string mnt = !mount_point.empty() ? mount_point : "/"; - if (!mnt.empty() && mnt[0] == '/') { - base_dirs_.push_back({mnt, dir, std::move(headers)}); - return true; - } +inline bool Server::set_base_dir(const char *path) { + if (detail::is_dir(path)) { + base_dir_ = path; + return true; } return false; } -inline bool Server::remove_mount_point(const std::string &mount_point) { - for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) { - if (it->mount_point == mount_point) { - base_dirs_.erase(it); - return true; - } - } - return false; +inline void Server::set_error_handler(Handler handler) { + error_handler_ = handler; } -inline Server & -Server::set_file_extension_and_mimetype_mapping(const std::string &ext, - const std::string &mime) { - file_extension_and_mimetype_map_[ext] = mime; - return *this; -} +inline void Server::set_logger(Logger logger) { logger_ = logger; } -inline Server &Server::set_default_file_mimetype(const std::string &mime) { - default_file_mimetype_ = mime; - return *this; -} - -inline Server &Server::set_file_request_handler(Handler handler) { - file_request_handler_ = std::move(handler); - return *this; -} - -inline Server &Server::set_error_handler(HandlerWithResponse handler) { - error_handler_ = std::move(handler); - return *this; -} - -inline Server &Server::set_error_handler(Handler handler) { - error_handler_ = [handler](const Request &req, Response &res) { - handler(req, res); - return HandlerResponse::Handled; - }; - return *this; -} - -inline Server &Server::set_exception_handler(ExceptionHandler handler) { - exception_handler_ = std::move(handler); - return *this; -} - -inline Server &Server::set_pre_routing_handler(HandlerWithResponse handler) { - pre_routing_handler_ = std::move(handler); - return *this; -} - -inline Server &Server::set_post_routing_handler(Handler handler) { - post_routing_handler_ = std::move(handler); - return *this; -} - -inline Server &Server::set_logger(Logger logger) { - logger_ = std::move(logger); - return *this; -} - -inline Server & -Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) { - expect_100_continue_handler_ = std::move(handler); - return *this; -} - -inline Server &Server::set_address_family(int family) { - address_family_ = family; - return *this; -} - -inline Server &Server::set_tcp_nodelay(bool on) { - tcp_nodelay_ = on; - return *this; -} - -inline Server &Server::set_socket_options(SocketOptions socket_options) { - socket_options_ = std::move(socket_options); - return *this; -} - -inline Server &Server::set_default_headers(Headers headers) { - default_headers_ = std::move(headers); - return *this; -} - -inline Server &Server::set_header_writer( - std::function const &writer) { - header_writer_ = writer; - return *this; -} - -inline Server &Server::set_keep_alive_max_count(size_t count) { +inline void Server::set_keep_alive_max_count(size_t count) { keep_alive_max_count_ = count; - return *this; } -inline Server &Server::set_keep_alive_timeout(time_t sec) { - keep_alive_timeout_sec_ = sec; - return *this; -} - -inline Server &Server::set_read_timeout(time_t sec, time_t usec) { - read_timeout_sec_ = sec; - read_timeout_usec_ = usec; - return *this; -} - -inline Server &Server::set_write_timeout(time_t sec, time_t usec) { - write_timeout_sec_ = sec; - write_timeout_usec_ = usec; - return *this; -} - -inline Server &Server::set_idle_interval(time_t sec, time_t usec) { - idle_interval_sec_ = sec; - idle_interval_usec_ = usec; - return *this; -} - -inline Server &Server::set_payload_max_length(size_t length) { +inline void Server::set_payload_max_length(uint64_t length) { payload_max_length_ = length; - return *this; } -inline bool Server::bind_to_port(const std::string &host, int port, - int socket_flags) { - return bind_internal(host, port, socket_flags) >= 0; -} -inline int Server::bind_to_any_port(const std::string &host, int socket_flags) { +inline int Server::bind_to_any_port(const char *host, int socket_flags) { return bind_internal(host, 0, socket_flags); } -inline bool Server::listen_after_bind() { - auto se = detail::scope_exit([&]() { done_ = true; }); +inline bool Server::listen_after_bind() { return listen_internal(); } + +inline bool Server::listen(const char *host, int port, int socket_flags) { + if (bind_internal(host, port, socket_flags) < 0) return false; return listen_internal(); } -inline bool Server::listen(const std::string &host, int port, - int socket_flags) { - auto se = detail::scope_exit([&]() { done_ = true; }); - return bind_to_port(host, port, socket_flags) && listen_internal(); -} - inline bool Server::is_running() const { return is_running_; } -inline void Server::wait_until_ready() const { - while (!is_running() && !done_) { - std::this_thread::sleep_for(std::chrono::milliseconds{1}); - } -} - inline void Server::stop() { if (is_running_) { assert(svr_sock_ != INVALID_SOCKET); @@ -5923,389 +1723,142 @@ inline void Server::stop() { } } -inline bool Server::parse_request_line(const char *s, Request &req) const { - auto len = strlen(s); - if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; } - len -= 2; +inline bool Server::parse_request_line(const char *s, Request &req) { + static std::regex re("(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS) " + "(([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n"); - { - size_t count = 0; + std::cmatch m; + if (std::regex_match(s, m, re)) { + req.version = std::string(m[5]); + req.method = std::string(m[1]); + req.target = std::string(m[2]); + req.path = detail::decode_url(m[3]); - detail::split(s, s + len, ' ', [&](const char *b, const char *e) { - switch (count) { - case 0: req.method = std::string(b, e); break; - case 1: req.target = std::string(b, e); break; - case 2: req.version = std::string(b, e); break; - default: break; - } - count++; - }); + // Parse query text + auto len = std::distance(m[4].first, m[4].second); + if (len > 0) { detail::parse_query_text(m[4], req.params); } - if (count != 3) { return false; } + return true; } - static const std::set methods{ - "GET", "HEAD", "POST", "PUT", "DELETE", - "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"}; - - if (methods.find(req.method) == methods.end()) { return false; } - - if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; } - - { - // Skip URL fragment - for (size_t i = 0; i < req.target.size(); i++) { - if (req.target[i] == '#') { - req.target.erase(i); - break; - } - } - - size_t count = 0; - - detail::split(req.target.data(), req.target.data() + req.target.size(), '?', - 2, [&](const char *b, const char *e) { - switch (count) { - case 0: - req.path = detail::decode_url(std::string(b, e), false); - break; - case 1: { - if (e - b > 0) { - detail::parse_query_text(std::string(b, e), req.params); - } - break; - } - default: break; - } - count++; - }); - - if (count > 2) { return false; } - } - - return true; + return false; } -inline bool Server::write_response(Stream &strm, bool close_connection, - Request &req, Response &res) { - // NOTE: `req.ranges` should be empty, otherwise it will be applied - // incorrectly to the error content. - req.ranges.clear(); - return write_response_core(strm, close_connection, req, res, false); -} - -inline bool Server::write_response_with_content(Stream &strm, - bool close_connection, - const Request &req, - Response &res) { - return write_response_core(strm, close_connection, req, res, true); -} - -inline bool Server::write_response_core(Stream &strm, bool close_connection, - const Request &req, Response &res, - bool need_apply_ranges) { +inline void Server::write_response(Stream &strm, bool last_connection, + const Request &req, Response &res) { assert(res.status != -1); - if (400 <= res.status && error_handler_ && - error_handler_(req, res) == HandlerResponse::Handled) { - need_apply_ranges = true; - } + if (400 <= res.status && error_handler_) { error_handler_(req, res); } - std::string content_type; - std::string boundary; - if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); } + // Response line + strm.write_format("HTTP/1.1 %d %s\r\n", res.status, + detail::status_message(res.status)); - // Prepare additional headers - if (close_connection || req.get_header_value("Connection") == "close") { + // Headers + if (last_connection || req.get_header_value("Connection") == "close") { res.set_header("Connection", "close"); + } + + if (!last_connection && req.get_header_value("Connection") == "Keep-Alive") { + res.set_header("Connection", "Keep-Alive"); + } + + if (res.body.empty()) { + if (!res.has_header("Content-Length")) { + if (res.content_producer) { + // Streamed response + res.set_header("Transfer-Encoding", "chunked"); + } else { + res.set_header("Content-Length", "0"); + } + } } else { - std::stringstream ss; - ss << "timeout=" << keep_alive_timeout_sec_ - << ", max=" << keep_alive_max_count_; - res.set_header("Keep-Alive", ss.str()); - } +#ifdef CPPHTTPLIB_ZLIB_SUPPORT + // TODO: 'Accpet-Encoding' has gzip, not gzip;q=0 + const auto &encodings = req.get_header_value("Accept-Encoding"); + if (encodings.find("gzip") != std::string::npos && + detail::can_compress(res.get_header_value("Content-Type"))) { + if (detail::compress(res.body)) { + res.set_header("Content-Encoding", "gzip"); + } + } +#endif - if (!res.has_header("Content-Type") && - (!res.body.empty() || res.content_length_ > 0 || res.content_provider_)) { - res.set_header("Content-Type", "text/plain"); - } - - if (!res.has_header("Content-Length") && res.body.empty() && - !res.content_length_ && !res.content_provider_) { - res.set_header("Content-Length", "0"); - } - - if (!res.has_header("Accept-Ranges") && req.method == "HEAD") { - res.set_header("Accept-Ranges", "bytes"); - } - - if (post_routing_handler_) { post_routing_handler_(req, res); } - - // Response line and headers - { - detail::BufferStream bstrm; - - if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status, - status_message(res.status))) { - return false; + if (!res.has_header("Content-Type")) { + res.set_header("Content-Type", "text/plain"); } - if (!header_writer_(bstrm, res.headers)) { return false; } - - // Flush buffer - auto &data = bstrm.get_buffer(); - detail::write_data(strm, data.data(), data.size()); + auto length = std::to_string(res.body.size()); + res.set_header("Content-Length", length.c_str()); } + detail::write_headers(strm, res); + // Body - auto ret = true; if (req.method != "HEAD") { if (!res.body.empty()) { - if (!detail::write_data(strm, res.body.data(), res.body.size())) { - ret = false; - } - } else if (res.content_provider_) { - if (write_content_with_provider(strm, req, res, boundary, content_type)) { - res.content_provider_success_ = true; - } else { - ret = false; - } + strm.write(res.body.c_str(), res.body.size()); + } else if (res.content_producer) { + detail::write_content_chunked(strm, res); } } // Log if (logger_) { logger_(req, res); } - - return ret; } -inline bool -Server::write_content_with_provider(Stream &strm, const Request &req, - Response &res, const std::string &boundary, - const std::string &content_type) { - auto is_shutting_down = [this]() { - return this->svr_sock_ == INVALID_SOCKET; - }; +inline bool Server::handle_file_request(Request &req, Response &res) { + if (!base_dir_.empty() && detail::is_valid_path(req.path)) { + std::string path = base_dir_ + req.path; - if (res.content_length_ > 0) { - if (req.ranges.empty()) { - return detail::write_content(strm, res.content_provider_, 0, - res.content_length_, is_shutting_down); - } else if (req.ranges.size() == 1) { - auto offset_and_length = detail::get_range_offset_and_length( - req.ranges[0], res.content_length_); + if (!path.empty() && path.back() == '/') { path += "index.html"; } - return detail::write_content(strm, res.content_provider_, - offset_and_length.first, - offset_and_length.second, is_shutting_down); - } else { - return detail::write_multipart_ranges_data( - strm, req, res, boundary, content_type, res.content_length_, - is_shutting_down); - } - } else { - if (res.is_chunked_content_provider_) { - auto type = detail::encoding_type(req, res); - - std::unique_ptr compressor; - if (type == detail::EncodingType::Gzip) { -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - compressor = detail::make_unique(); -#endif - } else if (type == detail::EncodingType::Brotli) { -#ifdef CPPHTTPLIB_BROTLI_SUPPORT - compressor = detail::make_unique(); -#endif - } else { - compressor = detail::make_unique(); - } - assert(compressor != nullptr); - - return detail::write_content_chunked(strm, res.content_provider_, - is_shutting_down, *compressor); - } else { - return detail::write_content_without_length(strm, res.content_provider_, - is_shutting_down); - } - } -} - -inline bool Server::read_content(Stream &strm, Request &req, Response &res) { - MultipartFormDataMap::iterator cur; - auto file_count = 0; - if (read_content_core( - strm, req, res, - // Regular - [&](const char *buf, size_t n) { - if (req.body.size() + n > req.body.max_size()) { return false; } - req.body.append(buf, n); - return true; - }, - // Multipart - [&](const MultipartFormData &file) { - if (file_count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) { - return false; - } - cur = req.files.emplace(file.name, file); - return true; - }, - [&](const char *buf, size_t n) { - auto &content = cur->second.content; - if (content.size() + n > content.max_size()) { return false; } - content.append(buf, n); - return true; - })) { - const auto &content_type = req.get_header_value("Content-Type"); - if (!content_type.find("application/x-www-form-urlencoded")) { - if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) { - res.status = StatusCode::PayloadTooLarge_413; // NOTE: should be 414? - return false; - } - detail::parse_query_text(req.body, req.params); - } - return true; - } - return false; -} - -inline bool Server::read_content_with_content_receiver( - Stream &strm, Request &req, Response &res, ContentReceiver receiver, - MultipartContentHeader multipart_header, - ContentReceiver multipart_receiver) { - return read_content_core(strm, req, res, std::move(receiver), - std::move(multipart_header), - std::move(multipart_receiver)); -} - -inline bool -Server::read_content_core(Stream &strm, Request &req, Response &res, - ContentReceiver receiver, - MultipartContentHeader multipart_header, - ContentReceiver multipart_receiver) const { - detail::MultipartFormDataParser multipart_form_data_parser; - ContentReceiverWithProgress out; - - if (req.is_multipart_form_data()) { - const auto &content_type = req.get_header_value("Content-Type"); - std::string boundary; - if (!detail::parse_multipart_boundary(content_type, boundary)) { - res.status = StatusCode::BadRequest_400; - return false; - } - - multipart_form_data_parser.set_boundary(std::move(boundary)); - out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) { - /* For debug - size_t pos = 0; - while (pos < n) { - auto read_size = (std::min)(1, n - pos); - auto ret = multipart_form_data_parser.parse( - buf + pos, read_size, multipart_receiver, multipart_header); - if (!ret) { return false; } - pos += read_size; - } + if (detail::is_file(path)) { + detail::read_file(path, res.body); + auto type = detail::find_content_type(path); + if (type) { res.set_header("Content-Type", type); } + res.status = 200; return true; - */ - return multipart_form_data_parser.parse(buf, n, multipart_receiver, - multipart_header); - }; - } else { - out = [receiver](const char *buf, size_t n, uint64_t /*off*/, - uint64_t /*len*/) { return receiver(buf, n); }; - } - - if (req.method == "DELETE" && !req.has_header("Content-Length")) { - return true; - } - - if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr, - out, true)) { - return false; - } - - if (req.is_multipart_form_data()) { - if (!multipart_form_data_parser.is_valid()) { - res.status = StatusCode::BadRequest_400; - return false; } } - return true; -} - -inline bool Server::handle_file_request(const Request &req, Response &res, - bool head) { - for (const auto &entry : base_dirs_) { - // Prefix match - if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) { - std::string sub_path = "/" + req.path.substr(entry.mount_point.size()); - if (detail::is_valid_path(sub_path)) { - auto path = entry.base_dir + sub_path; - if (path.back() == '/') { path += "index.html"; } - - if (detail::is_file(path)) { - for (const auto &kv : entry.headers) { - res.set_header(kv.first, kv.second); - } - - auto mm = std::make_shared(path.c_str()); - if (!mm->is_open()) { return false; } - - res.set_content_provider( - mm->size(), - detail::find_content_type(path, file_extension_and_mimetype_map_, - default_file_mimetype_), - [mm](size_t offset, size_t length, DataSink &sink) -> bool { - sink.write(mm->data() + offset, length); - return true; - }); - - if (!head && file_request_handler_) { - file_request_handler_(req, res); - } - - return true; - } - } - } - } return false; } -inline socket_t -Server::create_server_socket(const std::string &host, int port, - int socket_flags, - SocketOptions socket_options) const { +inline socket_t Server::create_server_socket(const char *host, int port, + int socket_flags) const { return detail::create_socket( - host, std::string(), port, address_family_, socket_flags, tcp_nodelay_, - std::move(socket_options), + host, port, [](socket_t sock, struct addrinfo &ai) -> bool { - if (::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { + if (::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { + return false; + } + if (::listen(sock, 5)) { // Listen through 5 channels return false; } - if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; } return true; - }); + }, + socket_flags); } -inline int Server::bind_internal(const std::string &host, int port, - int socket_flags) { +inline int Server::bind_internal(const char *host, int port, int socket_flags) { if (!is_valid()) { return -1; } - svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_); + svr_sock_ = create_server_socket(host, port, socket_flags); if (svr_sock_ == INVALID_SOCKET) { return -1; } if (port == 0) { - struct sockaddr_storage addr; - socklen_t addr_len = sizeof(addr); - if (getsockname(svr_sock_, reinterpret_cast(&addr), - &addr_len) == -1) { + struct sockaddr_storage address; + socklen_t len = sizeof(address); + if (getsockname(svr_sock_, reinterpret_cast(&address), + &len) == -1) { return -1; } - if (addr.ss_family == AF_INET) { - return ntohs(reinterpret_cast(&addr)->sin_port); - } else if (addr.ss_family == AF_INET6) { - return ntohs(reinterpret_cast(&addr)->sin6_port); + if (address.ss_family == AF_INET) { + return ntohs(reinterpret_cast(&address)->sin_port); + } else if (address.ss_family == AF_INET6) { + return ntohs( + reinterpret_cast(&address)->sin6_port); } else { return -1; } @@ -6316,172 +1869,87 @@ inline int Server::bind_internal(const std::string &host, int port, inline bool Server::listen_internal() { auto ret = true; + is_running_ = true; - auto se = detail::scope_exit([&]() { is_running_ = false; }); - { - std::unique_ptr task_queue(new_task_queue()); - - while (svr_sock_ != INVALID_SOCKET) { -#ifndef _WIN32 - if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) { -#endif - auto val = detail::select_read(svr_sock_, idle_interval_sec_, - idle_interval_usec_); - if (val == 0) { // Timeout - task_queue->on_idle(); - continue; - } -#ifndef _WIN32 - } -#endif - socket_t sock = accept(svr_sock_, nullptr, nullptr); - - if (sock == INVALID_SOCKET) { - if (errno == EMFILE) { - // The per-process limit of open file descriptors has been reached. - // Try to accept new connections after a short sleep. - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } else if (errno == EINTR || errno == EAGAIN) { - continue; - } - if (svr_sock_ != INVALID_SOCKET) { - detail::close_socket(svr_sock_); - ret = false; - } else { - ; // The server socket was closed by user. - } - break; - } - - { -#ifdef _WIN32 - auto timeout = static_cast(read_timeout_sec_ * 1000 + - read_timeout_usec_ / 1000); - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(read_timeout_sec_); - tv.tv_usec = static_cast(read_timeout_usec_); - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } - { - -#ifdef _WIN32 - auto timeout = static_cast(write_timeout_sec_ * 1000 + - write_timeout_usec_ / 1000); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&timeout), sizeof(timeout)); -#else - timeval tv; - tv.tv_sec = static_cast(write_timeout_sec_); - tv.tv_usec = static_cast(write_timeout_usec_); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, - reinterpret_cast(&tv), sizeof(tv)); -#endif - } - - if (!task_queue->enqueue( - [this, sock]() { process_and_close_socket(sock); })) { - detail::shutdown_socket(sock); - detail::close_socket(sock); - } + for (;;) { + if (svr_sock_ == INVALID_SOCKET) { + // The server socket was closed by 'stop' method. + break; } - task_queue->shutdown(); + auto val = detail::select_read(svr_sock_, 0, 100000); + + if (val == 0) { // Timeout + continue; + } + + socket_t sock = accept(svr_sock_, nullptr, nullptr); + + if (sock == INVALID_SOCKET) { + if (svr_sock_ != INVALID_SOCKET) { + detail::close_socket(svr_sock_); + ret = false; + } else { + ; // The server socket was closed by user. + } + break; + } + + // TODO: Use thread pool... + std::thread([=]() { + { + std::lock_guard guard(running_threads_mutex_); + running_threads_++; + } + + read_and_close_socket(sock); + + { + std::lock_guard guard(running_threads_mutex_); + running_threads_--; + } + }).detach(); } + // TODO: Use thread pool... + for (;;) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::lock_guard guard(running_threads_mutex_); + if (!running_threads_) { break; } + } + + is_running_ = false; + return ret; } -inline bool Server::routing(Request &req, Response &res, Stream &strm) { - if (pre_routing_handler_ && - pre_routing_handler_(req, res) == HandlerResponse::Handled) { - return true; - } +inline bool Server::routing(Request &req, Response &res) { + if (req.method == "GET" && handle_file_request(req, res)) { return true; } - // File handler - auto is_head_request = req.method == "HEAD"; - if ((req.method == "GET" || is_head_request) && - handle_file_request(req, res, is_head_request)) { - return true; - } - - if (detail::expect_content(req)) { - // Content reader handler - { - ContentReader reader( - [&](ContentReceiver receiver) { - return read_content_with_content_receiver( - strm, req, res, std::move(receiver), nullptr, nullptr); - }, - [&](MultipartContentHeader header, ContentReceiver receiver) { - return read_content_with_content_receiver(strm, req, res, nullptr, - std::move(header), - std::move(receiver)); - }); - - if (req.method == "POST") { - if (dispatch_request_for_content_reader( - req, res, std::move(reader), - post_handlers_for_content_reader_)) { - return true; - } - } else if (req.method == "PUT") { - if (dispatch_request_for_content_reader( - req, res, std::move(reader), - put_handlers_for_content_reader_)) { - return true; - } - } else if (req.method == "PATCH") { - if (dispatch_request_for_content_reader( - req, res, std::move(reader), - patch_handlers_for_content_reader_)) { - return true; - } - } else if (req.method == "DELETE") { - if (dispatch_request_for_content_reader( - req, res, std::move(reader), - delete_handlers_for_content_reader_)) { - return true; - } - } - } - - // Read content into `req.body` - if (!read_content(strm, req, res)) { return false; } - } - - // Regular handler if (req.method == "GET" || req.method == "HEAD") { return dispatch_request(req, res, get_handlers_); } else if (req.method == "POST") { return dispatch_request(req, res, post_handlers_); } else if (req.method == "PUT") { return dispatch_request(req, res, put_handlers_); + } else if (req.method == "PATCH") { + return dispatch_request(req, res, patch_handlers_); } else if (req.method == "DELETE") { return dispatch_request(req, res, delete_handlers_); } else if (req.method == "OPTIONS") { return dispatch_request(req, res, options_handlers_); - } else if (req.method == "PATCH") { - return dispatch_request(req, res, patch_handlers_); } - - res.status = StatusCode::BadRequest_400; return false; } inline bool Server::dispatch_request(Request &req, Response &res, - const Handlers &handlers) const { + Handlers &handlers) { for (const auto &x : handlers) { - const auto &matcher = x.first; + const auto &pattern = x.first; const auto &handler = x.second; - if (matcher->match(req)) { + if (std::regex_match(req.path, req.matches, pattern)) { handler(req, res); return true; } @@ -6489,769 +1957,186 @@ inline bool Server::dispatch_request(Request &req, Response &res, return false; } -inline void Server::apply_ranges(const Request &req, Response &res, - std::string &content_type, - std::string &boundary) const { - if (req.ranges.size() > 1) { - auto it = res.headers.find("Content-Type"); - if (it != res.headers.end()) { - content_type = it->second; - res.headers.erase(it); - } - - boundary = detail::make_multipart_data_boundary(); - - res.set_header("Content-Type", - "multipart/byteranges; boundary=" + boundary); - } - - auto type = detail::encoding_type(req, res); - - if (res.body.empty()) { - if (res.content_length_ > 0) { - size_t length = 0; - if (req.ranges.empty()) { - length = res.content_length_; - } else if (req.ranges.size() == 1) { - auto offset_and_length = detail::get_range_offset_and_length( - req.ranges[0], res.content_length_); - - length = offset_and_length.second; - - auto content_range = detail::make_content_range_header_field( - offset_and_length, res.content_length_); - res.set_header("Content-Range", content_range); - } else { - length = detail::get_multipart_ranges_data_length( - req, boundary, content_type, res.content_length_); - } - res.set_header("Content-Length", std::to_string(length)); - } else { - if (res.content_provider_) { - if (res.is_chunked_content_provider_) { - res.set_header("Transfer-Encoding", "chunked"); - if (type == detail::EncodingType::Gzip) { - res.set_header("Content-Encoding", "gzip"); - } else if (type == detail::EncodingType::Brotli) { - res.set_header("Content-Encoding", "br"); - } - } - } - } - } else { - if (req.ranges.empty()) { - ; - } else if (req.ranges.size() == 1) { - auto offset_and_length = - detail::get_range_offset_and_length(req.ranges[0], res.body.size()); - auto offset = offset_and_length.first; - auto length = offset_and_length.second; - - auto content_range = detail::make_content_range_header_field( - offset_and_length, res.body.size()); - res.set_header("Content-Range", content_range); - - assert(offset + length <= res.body.size()); - res.body = res.body.substr(offset, length); - } else { - std::string data; - detail::make_multipart_ranges_data(req, res, boundary, content_type, - res.body.size(), data); - res.body.swap(data); - } - - if (type != detail::EncodingType::None) { - std::unique_ptr compressor; - std::string content_encoding; - - if (type == detail::EncodingType::Gzip) { -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - compressor = detail::make_unique(); - content_encoding = "gzip"; -#endif - } else if (type == detail::EncodingType::Brotli) { -#ifdef CPPHTTPLIB_BROTLI_SUPPORT - compressor = detail::make_unique(); - content_encoding = "br"; -#endif - } - - if (compressor) { - std::string compressed; - if (compressor->compress(res.body.data(), res.body.size(), true, - [&](const char *data, size_t data_len) { - compressed.append(data, data_len); - return true; - })) { - res.body.swap(compressed); - res.set_header("Content-Encoding", content_encoding); - } - } - } - - auto length = std::to_string(res.body.size()); - res.set_header("Content-Length", length); - } -} - -inline bool Server::dispatch_request_for_content_reader( - Request &req, Response &res, ContentReader content_reader, - const HandlersForContentReader &handlers) const { - for (const auto &x : handlers) { - const auto &matcher = x.first; - const auto &handler = x.second; - - if (matcher->match(req)) { - handler(req, res, content_reader); - return true; - } - } - return false; -} - inline bool -Server::process_request(Stream &strm, bool close_connection, - bool &connection_closed, - const std::function &setup_request) { - std::array buf{}; +Server::process_request(Stream &strm, bool last_connection, + bool &connection_close, + std::function setup_request) { + const auto bufsiz = 2048; + char buf[bufsiz]; - detail::stream_line_reader line_reader(strm, buf.data(), buf.size()); + detail::stream_line_reader reader(strm, buf, bufsiz); // Connection has been closed on client - if (!line_reader.getline()) { return false; } + if (!reader.getline()) { return false; } Request req; - Response res; - res.version = "HTTP/1.1"; - res.headers = default_headers_; -#ifdef _WIN32 - // TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL). -#else -#ifndef CPPHTTPLIB_USE_POLL - // Socket file descriptor exceeded FD_SETSIZE... - if (strm.socket() >= FD_SETSIZE) { - Headers dummy; - detail::read_headers(strm, dummy); - res.status = StatusCode::InternalServerError_500; - return write_response(strm, close_connection, req, res); - } -#endif -#endif + res.version = "HTTP/1.1"; // Check if the request URI doesn't exceed the limit - if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { - Headers dummy; - detail::read_headers(strm, dummy); - res.status = StatusCode::UriTooLong_414; - return write_response(strm, close_connection, req, res); + if (reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { + res.status = 414; + write_response(strm, last_connection, req, res); + return true; } // Request line and headers - if (!parse_request_line(line_reader.ptr(), req) || + if (!parse_request_line(reader.ptr(), req) || !detail::read_headers(strm, req.headers)) { - res.status = StatusCode::BadRequest_400; - return write_response(strm, close_connection, req, res); + res.status = 400; + write_response(strm, last_connection, req, res); + return true; } if (req.get_header_value("Connection") == "close") { - connection_closed = true; + connection_close = true; } - if (req.version == "HTTP/1.0" && - req.get_header_value("Connection") != "Keep-Alive") { - connection_closed = true; - } + req.set_header("REMOTE_ADDR", strm.get_remote_addr().c_str()); - strm.get_remote_ip_and_port(req.remote_addr, req.remote_port); - req.set_header("REMOTE_ADDR", req.remote_addr); - req.set_header("REMOTE_PORT", std::to_string(req.remote_port)); + // Body + if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") { + if (!detail::read_content( + strm, req, payload_max_length_, res.status, Progress(), + [&](const char *buf, size_t n) { req.body.append(buf, n); })) { + write_response(strm, last_connection, req, res); + return true; + } - strm.get_local_ip_and_port(req.local_addr, req.local_port); - req.set_header("LOCAL_ADDR", req.local_addr); - req.set_header("LOCAL_PORT", std::to_string(req.local_port)); + const auto &content_type = req.get_header_value("Content-Type"); - if (req.has_header("Range")) { - const auto &range_header_value = req.get_header_value("Range"); - if (!detail::parse_range_header(range_header_value, req.ranges)) { - res.status = StatusCode::RangeNotSatisfiable_416; - return write_response(strm, close_connection, req, res); + if (!content_type.find("application/x-www-form-urlencoded")) { + detail::parse_query_text(req.body, req.params); + } else if (!content_type.find("multipart/form-data")) { + std::string boundary; + if (!detail::parse_multipart_boundary(content_type, boundary) || + !detail::parse_multipart_formdata(boundary, req.body, req.files)) { + res.status = 400; + write_response(strm, last_connection, req, res); + return true; + } } } + // TODO: Add additional request info if (setup_request) { setup_request(req); } - if (req.get_header_value("Expect") == "100-continue") { - int status = StatusCode::Continue_100; - if (expect_100_continue_handler_) { - status = expect_100_continue_handler_(req, res); - } - switch (status) { - case StatusCode::Continue_100: - case StatusCode::ExpectationFailed_417: - strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status, - status_message(status)); - break; - default: return write_response(strm, close_connection, req, res); - } - } - - // Routing - auto routed = false; -#ifdef CPPHTTPLIB_NO_EXCEPTIONS - routed = routing(req, res, strm); -#else - try { - routed = routing(req, res, strm); - } catch (std::exception &e) { - if (exception_handler_) { - auto ep = std::current_exception(); - exception_handler_(req, res, ep); - routed = true; - } else { - res.status = StatusCode::InternalServerError_500; - std::string val; - auto s = e.what(); - for (size_t i = 0; s[i]; i++) { - switch (s[i]) { - case '\r': val += "\\r"; break; - case '\n': val += "\\n"; break; - default: val += s[i]; break; - } - } - res.set_header("EXCEPTION_WHAT", val); - } - } catch (...) { - if (exception_handler_) { - auto ep = std::current_exception(); - exception_handler_(req, res, ep); - routed = true; - } else { - res.status = StatusCode::InternalServerError_500; - res.set_header("EXCEPTION_WHAT", "UNKNOWN"); - } - } -#endif - if (routed) { - if (res.status == -1) { - res.status = req.ranges.empty() ? StatusCode::OK_200 - : StatusCode::PartialContent_206; - } - - if (detail::range_error(req, res)) { - res.body.clear(); - res.content_length_ = 0; - res.content_provider_ = nullptr; - res.status = StatusCode::RangeNotSatisfiable_416; - return write_response(strm, close_connection, req, res); - } - - return write_response_with_content(strm, close_connection, req, res); + if (routing(req, res)) { + if (res.status == -1) { res.status = 200; } } else { - if (res.status == -1) { res.status = StatusCode::NotFound_404; } - - return write_response(strm, close_connection, req, res); + res.status = 404; } + + write_response(strm, last_connection, req, res); + return true; } inline bool Server::is_valid() const { return true; } -inline bool Server::process_and_close_socket(socket_t sock) { - auto ret = detail::process_server_socket( - svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_, - read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, - write_timeout_usec_, - [this](Stream &strm, bool close_connection, bool &connection_closed) { - return process_request(strm, close_connection, connection_closed, - nullptr); +inline bool Server::read_and_close_socket(socket_t sock) { + return detail::read_and_close_socket( + sock, keep_alive_max_count_, + [this](Stream &strm, bool last_connection, bool &connection_close) { + return process_request(strm, last_connection, connection_close); }); - - detail::shutdown_socket(sock); - detail::close_socket(sock); - return ret; } // HTTP client implementation -inline ClientImpl::ClientImpl(const std::string &host) - : ClientImpl(host, 80, std::string(), std::string()) {} +inline Client::Client(const char *host, int port, time_t timeout_sec) + : host_(host), port_(port), timeout_sec_(timeout_sec), + host_and_port_(host_ + ":" + std::to_string(port_)) {} -inline ClientImpl::ClientImpl(const std::string &host, int port) - : ClientImpl(host, port, std::string(), std::string()) {} +inline Client::~Client() {} -inline ClientImpl::ClientImpl(const std::string &host, int port, - const std::string &client_cert_path, - const std::string &client_key_path) - : host_(host), port_(port), - host_and_port_(adjust_host_string(host) + ":" + std::to_string(port)), - client_cert_path_(client_cert_path), client_key_path_(client_key_path) {} +inline bool Client::is_valid() const { return true; } -inline ClientImpl::~ClientImpl() { - std::lock_guard guard(socket_mutex_); - shutdown_socket(socket_); - close_socket(socket_); -} +inline socket_t Client::create_client_socket() const { + return detail::create_socket( + host_.c_str(), port_, [=](socket_t sock, struct addrinfo &ai) -> bool { + detail::set_nonblocking(sock, true); -inline bool ClientImpl::is_valid() const { return true; } - -inline void ClientImpl::copy_settings(const ClientImpl &rhs) { - client_cert_path_ = rhs.client_cert_path_; - client_key_path_ = rhs.client_key_path_; - connection_timeout_sec_ = rhs.connection_timeout_sec_; - read_timeout_sec_ = rhs.read_timeout_sec_; - read_timeout_usec_ = rhs.read_timeout_usec_; - write_timeout_sec_ = rhs.write_timeout_sec_; - write_timeout_usec_ = rhs.write_timeout_usec_; - basic_auth_username_ = rhs.basic_auth_username_; - basic_auth_password_ = rhs.basic_auth_password_; - bearer_token_auth_token_ = rhs.bearer_token_auth_token_; -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - digest_auth_username_ = rhs.digest_auth_username_; - digest_auth_password_ = rhs.digest_auth_password_; -#endif - keep_alive_ = rhs.keep_alive_; - follow_location_ = rhs.follow_location_; - url_encode_ = rhs.url_encode_; - address_family_ = rhs.address_family_; - tcp_nodelay_ = rhs.tcp_nodelay_; - socket_options_ = rhs.socket_options_; - compress_ = rhs.compress_; - decompress_ = rhs.decompress_; - interface_ = rhs.interface_; - proxy_host_ = rhs.proxy_host_; - proxy_port_ = rhs.proxy_port_; - proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_; - proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_; - proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_; -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_; - proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_; -#endif -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - ca_cert_file_path_ = rhs.ca_cert_file_path_; - ca_cert_dir_path_ = rhs.ca_cert_dir_path_; - ca_cert_store_ = rhs.ca_cert_store_; -#endif -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - server_certificate_verification_ = rhs.server_certificate_verification_; -#endif - logger_ = rhs.logger_; -} - -inline socket_t ClientImpl::create_client_socket(Error &error) const { - if (!proxy_host_.empty() && proxy_port_ != -1) { - return detail::create_client_socket( - proxy_host_, std::string(), proxy_port_, address_family_, tcp_nodelay_, - socket_options_, connection_timeout_sec_, connection_timeout_usec_, - read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, - write_timeout_usec_, interface_, error); - } - - // Check is custom IP specified for host_ - std::string ip; - auto it = addr_map_.find(host_); - if (it != addr_map_.end()) { ip = it->second; } - - return detail::create_client_socket( - host_, ip, port_, address_family_, tcp_nodelay_, socket_options_, - connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_, - read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_, - error); -} - -inline bool ClientImpl::create_and_connect_socket(Socket &socket, - Error &error) { - auto sock = create_client_socket(error); - if (sock == INVALID_SOCKET) { return false; } - socket.sock = sock; - return true; -} - -inline void ClientImpl::shutdown_ssl(Socket & /*socket*/, - bool /*shutdown_gracefully*/) { - // If there are any requests in flight from threads other than us, then it's - // a thread-unsafe race because individual ssl* objects are not thread-safe. - assert(socket_requests_in_flight_ == 0 || - socket_requests_are_from_thread_ == std::this_thread::get_id()); -} - -inline void ClientImpl::shutdown_socket(Socket &socket) const { - if (socket.sock == INVALID_SOCKET) { return; } - detail::shutdown_socket(socket.sock); -} - -inline void ClientImpl::close_socket(Socket &socket) { - // If there are requests in flight in another thread, usually closing - // the socket will be fine and they will simply receive an error when - // using the closed socket, but it is still a bug since rarely the OS - // may reassign the socket id to be used for a new socket, and then - // suddenly they will be operating on a live socket that is different - // than the one they intended! - assert(socket_requests_in_flight_ == 0 || - socket_requests_are_from_thread_ == std::this_thread::get_id()); - - // It is also a bug if this happens while SSL is still active -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - assert(socket.ssl == nullptr); -#endif - if (socket.sock == INVALID_SOCKET) { return; } - detail::close_socket(socket.sock); - socket.sock = INVALID_SOCKET; -} - -inline bool ClientImpl::read_response_line(Stream &strm, const Request &req, - Response &res) const { - std::array buf{}; - - detail::stream_line_reader line_reader(strm, buf.data(), buf.size()); - - if (!line_reader.getline()) { return false; } - -#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR - const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n"); -#else - const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n"); -#endif - - std::cmatch m; - if (!std::regex_match(line_reader.ptr(), m, re)) { - return req.method == "CONNECT"; - } - res.version = std::string(m[1]); - res.status = std::stoi(std::string(m[2])); - res.reason = std::string(m[3]); - - // Ignore '100 Continue' - while (res.status == StatusCode::Continue_100) { - if (!line_reader.getline()) { return false; } // CRLF - if (!line_reader.getline()) { return false; } // next response line - - if (!std::regex_match(line_reader.ptr(), m, re)) { return false; } - res.version = std::string(m[1]); - res.status = std::stoi(std::string(m[2])); - res.reason = std::string(m[3]); - } - - return true; -} - -inline bool ClientImpl::send(Request &req, Response &res, Error &error) { - std::lock_guard request_mutex_guard(request_mutex_); - auto ret = send_(req, res, error); - if (error == Error::SSLPeerCouldBeClosed_) { - assert(!ret); - ret = send_(req, res, error); - } - return ret; -} - -inline bool ClientImpl::send_(Request &req, Response &res, Error &error) { - { - std::lock_guard guard(socket_mutex_); - - // Set this to false immediately - if it ever gets set to true by the end of - // the request, we know another thread instructed us to close the socket. - socket_should_be_closed_when_request_is_done_ = false; - - auto is_alive = false; - if (socket_.is_open()) { - is_alive = detail::is_socket_alive(socket_.sock); - if (!is_alive) { - // Attempt to avoid sigpipe by shutting down nongracefully if it seems - // like the other side has already closed the connection Also, there - // cannot be any requests in flight from other threads since we locked - // request_mutex_, so safe to close everything immediately - const bool shutdown_gracefully = false; - shutdown_ssl(socket_, shutdown_gracefully); - shutdown_socket(socket_); - close_socket(socket_); - } - } - - if (!is_alive) { - if (!create_and_connect_socket(socket_, error)) { return false; } - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - // TODO: refactoring - if (is_ssl()) { - auto &scli = static_cast(*this); - if (!proxy_host_.empty() && proxy_port_ != -1) { - auto success = false; - if (!scli.connect_with_proxy(socket_, res, success, error)) { - return success; + auto ret = connect(sock, ai.ai_addr, static_cast(ai.ai_addrlen)); + if (ret < 0) { + if (detail::is_connection_error() || + !detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) { + detail::close_socket(sock); + return false; } } - if (!scli.initialize_ssl(socket_, error)) { return false; } - } -#endif - } - - // Mark the current socket as being in use so that it cannot be closed by - // anyone else while this request is ongoing, even though we will be - // releasing the mutex. - if (socket_requests_in_flight_ > 1) { - assert(socket_requests_are_from_thread_ == std::this_thread::get_id()); - } - socket_requests_in_flight_ += 1; - socket_requests_are_from_thread_ = std::this_thread::get_id(); - } - - for (const auto &header : default_headers_) { - if (req.headers.find(header.first) == req.headers.end()) { - req.headers.insert(header); - } - } - - auto ret = false; - auto close_connection = !keep_alive_; - - auto se = detail::scope_exit([&]() { - // Briefly lock mutex in order to mark that a request is no longer ongoing - std::lock_guard guard(socket_mutex_); - socket_requests_in_flight_ -= 1; - if (socket_requests_in_flight_ <= 0) { - assert(socket_requests_in_flight_ == 0); - socket_requests_are_from_thread_ = std::thread::id(); - } - - if (socket_should_be_closed_when_request_is_done_ || close_connection || - !ret) { - shutdown_ssl(socket_, true); - shutdown_socket(socket_); - close_socket(socket_); - } - }); - - ret = process_socket(socket_, [&](Stream &strm) { - return handle_request(strm, req, res, close_connection, error); - }); - - if (!ret) { - if (error == Error::Success) { error = Error::Unknown; } - } - - return ret; + detail::set_nonblocking(sock, false); + return true; + }); } -inline Result ClientImpl::send(const Request &req) { - auto req2 = req; - return send_(std::move(req2)); +inline bool Client::read_response_line(Stream &strm, Response &res) { + const auto bufsiz = 2048; + char buf[bufsiz]; + + detail::stream_line_reader reader(strm, buf, bufsiz); + + if (!reader.getline()) { return false; } + + const static std::regex re("(HTTP/1\\.[01]) (\\d+?) .*\r\n"); + + std::cmatch m; + if (std::regex_match(reader.ptr(), m, re)) { + res.version = std::string(m[1]); + res.status = std::stoi(std::string(m[2])); + } + + return true; } -inline Result ClientImpl::send_(Request &&req) { - auto res = detail::make_unique(); - auto error = Error::Success; - auto ret = send(req, *res, error); - return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)}; +inline bool Client::send(Request &req, Response &res) { + if (req.path.empty()) { return false; } + + auto sock = create_client_socket(); + if (sock == INVALID_SOCKET) { return false; } + + return read_and_close_socket(sock, req, res); } -inline bool ClientImpl::handle_request(Stream &strm, Request &req, - Response &res, bool close_connection, - Error &error) { - if (req.path.empty()) { - error = Error::Connection; - return false; - } +inline void Client::write_request(Stream &strm, Request &req) { + BufferStream bstrm; - auto req_save = req; + // Request line + auto path = detail::encode_url(req.path); - bool ret; - - if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) { - auto req2 = req; - req2.path = "http://" + host_and_port_ + req.path; - ret = process_request(strm, req2, res, close_connection, error); - req = req2; - req.path = req_save.path; - } else { - ret = process_request(strm, req, res, close_connection, error); - } - - if (!ret) { return false; } - - if (res.get_header_value("Connection") == "close" || - (res.version == "HTTP/1.0" && res.reason != "Connection established")) { - // TODO this requires a not-entirely-obvious chain of calls to be correct - // for this to be safe. - - // This is safe to call because handle_request is only called by send_ - // which locks the request mutex during the process. It would be a bug - // to call it from a different thread since it's a thread-safety issue - // to do these things to the socket if another thread is using the socket. - std::lock_guard guard(socket_mutex_); - shutdown_ssl(socket_, true); - shutdown_socket(socket_); - close_socket(socket_); - } - - if (300 < res.status && res.status < 400 && follow_location_) { - req = req_save; - ret = redirect(req, res, error); - } - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - if ((res.status == StatusCode::Unauthorized_401 || - res.status == StatusCode::ProxyAuthenticationRequired_407) && - req.authorization_count_ < 5) { - auto is_proxy = res.status == StatusCode::ProxyAuthenticationRequired_407; - const auto &username = - is_proxy ? proxy_digest_auth_username_ : digest_auth_username_; - const auto &password = - is_proxy ? proxy_digest_auth_password_ : digest_auth_password_; - - if (!username.empty() && !password.empty()) { - std::map auth; - if (detail::parse_www_authenticate(res, auth, is_proxy)) { - Request new_req = req; - new_req.authorization_count_ += 1; - new_req.headers.erase(is_proxy ? "Proxy-Authorization" - : "Authorization"); - new_req.headers.insert(detail::make_digest_authentication_header( - req, auth, new_req.authorization_count_, detail::random_string(10), - username, password, is_proxy)); - - Response new_res; - - ret = send(new_req, new_res, error); - if (ret) { res = new_res; } - } - } - } -#endif - - return ret; -} - -inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) { - if (req.redirect_count_ == 0) { - error = Error::ExceedRedirectCount; - return false; - } - - auto location = res.get_header_value("location"); - if (location.empty()) { return false; } - - const static std::regex re( - R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)"); - - std::smatch m; - if (!std::regex_match(location, m, re)) { return false; } - - auto scheme = is_ssl() ? "https" : "http"; - - auto next_scheme = m[1].str(); - auto next_host = m[2].str(); - if (next_host.empty()) { next_host = m[3].str(); } - auto port_str = m[4].str(); - auto next_path = m[5].str(); - auto next_query = m[6].str(); - - auto next_port = port_; - if (!port_str.empty()) { - next_port = std::stoi(port_str); - } else if (!next_scheme.empty()) { - next_port = next_scheme == "https" ? 443 : 80; - } - - if (next_scheme.empty()) { next_scheme = scheme; } - if (next_host.empty()) { next_host = host_; } - if (next_path.empty()) { next_path = "/"; } - - auto path = detail::decode_url(next_path, true) + next_query; - - if (next_scheme == scheme && next_host == host_ && next_port == port_) { - return detail::redirect(*this, req, res, path, location, error); - } else { - if (next_scheme == "https") { -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - SSLClient cli(next_host, next_port); - cli.copy_settings(*this); - if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); } - return detail::redirect(cli, req, res, path, location, error); -#else - return false; -#endif - } else { - ClientImpl cli(next_host, next_port); - cli.copy_settings(*this); - return detail::redirect(cli, req, res, path, location, error); - } - } -} - -inline bool ClientImpl::write_content_with_provider(Stream &strm, - const Request &req, - Error &error) const { - auto is_shutting_down = []() { return false; }; - - if (req.is_chunked_content_provider_) { - // TODO: Brotli support - std::unique_ptr compressor; -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - if (compress_) { - compressor = detail::make_unique(); - } else -#endif - { - compressor = detail::make_unique(); - } - - return detail::write_content_chunked(strm, req.content_provider_, - is_shutting_down, *compressor, error); - } else { - return detail::write_content(strm, req.content_provider_, 0, - req.content_length_, is_shutting_down, error); - } -} - -inline bool ClientImpl::write_request(Stream &strm, Request &req, - bool close_connection, Error &error) { - // Prepare additional headers - if (close_connection) { - if (!req.has_header("Connection")) { - req.set_header("Connection", "close"); - } - } + bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str()); + // Headers if (!req.has_header("Host")) { if (is_ssl()) { if (port_ == 443) { - req.set_header("Host", host_); + req.set_header("Host", host_.c_str()); } else { - req.set_header("Host", host_and_port_); + req.set_header("Host", host_and_port_.c_str()); } } else { if (port_ == 80) { - req.set_header("Host", host_); + req.set_header("Host", host_.c_str()); } else { - req.set_header("Host", host_and_port_); + req.set_header("Host", host_and_port_.c_str()); } } } if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); } -#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT if (!req.has_header("User-Agent")) { - auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION; - req.set_header("User-Agent", agent); + req.set_header("User-Agent", "cpp-httplib/0.2"); } -#endif + + // TODO: Support KeepAlive connection + // if (!req.has_header("Connection")) { + req.set_header("Connection", "close"); + // } if (req.body.empty()) { - if (req.content_provider_) { - if (!req.is_chunked_content_provider_) { - if (!req.has_header("Content-Length")) { - auto length = std::to_string(req.content_length_); - req.set_header("Content-Length", length); - } - } - } else { - if (req.method == "POST" || req.method == "PUT" || - req.method == "PATCH") { - req.set_header("Content-Length", "0"); - } + if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") { + req.set_header("Content-Length", "0"); } } else { if (!req.has_header("Content-Type")) { @@ -7260,953 +2145,247 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req, if (!req.has_header("Content-Length")) { auto length = std::to_string(req.body.size()); - req.set_header("Content-Length", length); + req.set_header("Content-Length", length.c_str()); } } - if (!basic_auth_password_.empty() || !basic_auth_username_.empty()) { - if (!req.has_header("Authorization")) { - req.headers.insert(make_basic_authentication_header( - basic_auth_username_, basic_auth_password_, false)); - } - } - - if (!proxy_basic_auth_username_.empty() && - !proxy_basic_auth_password_.empty()) { - if (!req.has_header("Proxy-Authorization")) { - req.headers.insert(make_basic_authentication_header( - proxy_basic_auth_username_, proxy_basic_auth_password_, true)); - } - } - - if (!bearer_token_auth_token_.empty()) { - if (!req.has_header("Authorization")) { - req.headers.insert(make_bearer_token_authentication_header( - bearer_token_auth_token_, false)); - } - } - - if (!proxy_bearer_token_auth_token_.empty()) { - if (!req.has_header("Proxy-Authorization")) { - req.headers.insert(make_bearer_token_authentication_header( - proxy_bearer_token_auth_token_, true)); - } - } - - // Request line and headers - { - detail::BufferStream bstrm; - - const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path; - bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str()); - - header_writer_(bstrm, req.headers); - - // Flush buffer - auto &data = bstrm.get_buffer(); - if (!detail::write_data(strm, data.data(), data.size())) { - error = Error::Write; - return false; - } - } + detail::write_headers(bstrm, req); // Body - if (req.body.empty()) { - return write_content_with_provider(strm, req, error); - } + if (!req.body.empty()) { bstrm.write(req.body.c_str(), req.body.size()); } - if (!detail::write_data(strm, req.body.data(), req.body.size())) { - error = Error::Write; - return false; - } - - return true; + // Flush buffer + auto &data = bstrm.get_buffer(); + strm.write(data.data(), data.size()); } -inline std::unique_ptr ClientImpl::send_with_content_provider( - Request &req, const char *body, size_t content_length, - ContentProvider content_provider, - ContentProviderWithoutLength content_provider_without_length, - const std::string &content_type, Error &error) { - if (!content_type.empty()) { req.set_header("Content-Type", content_type); } - -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - if (compress_) { req.set_header("Content-Encoding", "gzip"); } -#endif - -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - if (compress_ && !content_provider_without_length) { - // TODO: Brotli support - detail::gzip_compressor compressor; - - if (content_provider) { - auto ok = true; - size_t offset = 0; - DataSink data_sink; - - data_sink.write = [&](const char *data, size_t data_len) -> bool { - if (ok) { - auto last = offset + data_len == content_length; - - auto ret = compressor.compress( - data, data_len, last, - [&](const char *compressed_data, size_t compressed_data_len) { - req.body.append(compressed_data, compressed_data_len); - return true; - }); - - if (ret) { - offset += data_len; - } else { - ok = false; - } - } - return ok; - }; - - while (ok && offset < content_length) { - if (!content_provider(offset, content_length - offset, data_sink)) { - error = Error::Canceled; - return nullptr; - } - } - } else { - if (!compressor.compress(body, content_length, true, - [&](const char *data, size_t data_len) { - req.body.append(data, data_len); - return true; - })) { - error = Error::Compression; - return nullptr; - } - } - } else -#endif - { - if (content_provider) { - req.content_length_ = content_length; - req.content_provider_ = std::move(content_provider); - req.is_chunked_content_provider_ = false; - } else if (content_provider_without_length) { - req.content_length_ = 0; - req.content_provider_ = detail::ContentProviderAdapter( - std::move(content_provider_without_length)); - req.is_chunked_content_provider_ = true; - req.set_header("Transfer-Encoding", "chunked"); - } else { - req.body.assign(body, content_length); - } - } - - auto res = detail::make_unique(); - return send(req, *res, error) ? std::move(res) : nullptr; -} - -inline Result ClientImpl::send_with_content_provider( - const std::string &method, const std::string &path, const Headers &headers, - const char *body, size_t content_length, ContentProvider content_provider, - ContentProviderWithoutLength content_provider_without_length, - const std::string &content_type) { - Request req; - req.method = method; - req.headers = headers; - req.path = path; - - auto error = Error::Success; - - auto res = send_with_content_provider( - req, body, content_length, std::move(content_provider), - std::move(content_provider_without_length), content_type, error); - - return Result{std::move(res), error, std::move(req.headers)}; -} - -inline std::string -ClientImpl::adjust_host_string(const std::string &host) const { - if (host.find(':') != std::string::npos) { return "[" + host + "]"; } - return host; -} - -inline bool ClientImpl::process_request(Stream &strm, Request &req, - Response &res, bool close_connection, - Error &error) { +inline bool Client::process_request(Stream &strm, Request &req, Response &res, + bool &connection_close) { // Send request - if (!write_request(strm, req, close_connection, error)) { return false; } - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - if (is_ssl()) { - auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1; - if (!is_proxy_enabled) { - char buf[1]; - if (SSL_peek(socket_.ssl, buf, 1) == 0 && - SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) { - error = Error::SSLPeerCouldBeClosed_; - return false; - } - } - } -#endif + write_request(strm, req); // Receive response and headers - if (!read_response_line(strm, req, res) || + if (!read_response_line(strm, res) || !detail::read_headers(strm, res.headers)) { - error = Error::Read; return false; } + if (res.get_header_value("Connection") == "close" || + res.version == "HTTP/1.0") { + connection_close = true; + } + // Body - if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" && - req.method != "CONNECT") { - auto redirect = 300 < res.status && res.status < 400 && follow_location_; - - if (req.response_handler && !redirect) { - if (!req.response_handler(res)) { - error = Error::Canceled; - return false; - } - } - - auto out = - req.content_receiver - ? static_cast( - [&](const char *buf, size_t n, uint64_t off, uint64_t len) { - if (redirect) { return true; } - auto ret = req.content_receiver(buf, n, off, len); - if (!ret) { error = Error::Canceled; } - return ret; - }) - : static_cast( - [&](const char *buf, size_t n, uint64_t /*off*/, - uint64_t /*len*/) { - if (res.body.size() + n > res.body.max_size()) { - return false; - } - res.body.append(buf, n); - return true; - }); - - auto progress = [&](uint64_t current, uint64_t total) { - if (!req.progress || redirect) { return true; } - auto ret = req.progress(current, total); - if (!ret) { error = Error::Canceled; } - return ret; + if (req.method != "HEAD") { + ContentReceiver out = [&](const char *buf, size_t n) { + res.body.append(buf, n); }; + if (res.content_receiver) { + out = [&](const char *buf, size_t n) { res.content_receiver(buf, n); }; + } + int dummy_status; - if (!detail::read_content(strm, res, (std::numeric_limits::max)(), - dummy_status, std::move(progress), std::move(out), - decompress_)) { - if (error != Error::Canceled) { error = Error::Read; } + if (!detail::read_content(strm, res, std::numeric_limits::max(), + dummy_status, res.progress, out)) { return false; } } - // Log - if (logger_) { logger_(req, res); } - return true; } -inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider( - const std::string &boundary, const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) const { - size_t cur_item = 0; - size_t cur_start = 0; - // cur_item and cur_start are copied to within the std::function and maintain - // state between successive calls - return [&, cur_item, cur_start](size_t offset, - DataSink &sink) mutable -> bool { - if (!offset && !items.empty()) { - sink.os << detail::serialize_multipart_formdata(items, boundary, false); - return true; - } else if (cur_item < provider_items.size()) { - if (!cur_start) { - const auto &begin = detail::serialize_multipart_formdata_item_begin( - provider_items[cur_item], boundary); - offset += begin.size(); - cur_start = offset; - sink.os << begin; - } - - DataSink cur_sink; - auto has_data = true; - cur_sink.write = sink.write; - cur_sink.done = [&]() { has_data = false; }; - - if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) { - return false; - } - - if (!has_data) { - sink.os << detail::serialize_multipart_formdata_item_end(); - cur_item++; - cur_start = 0; - } - return true; - } else { - sink.os << detail::serialize_multipart_formdata_finish(boundary); - sink.done(); - return true; - } - }; +inline bool Client::read_and_close_socket(socket_t sock, Request &req, + Response &res) { + return detail::read_and_close_socket( + sock, 0, + [&](Stream &strm, bool /*last_connection*/, bool &connection_close) { + return process_request(strm, req, res, connection_close); + }); } -inline bool -ClientImpl::process_socket(const Socket &socket, - std::function callback) { - return detail::process_client_socket( - socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, - write_timeout_usec_, std::move(callback)); +inline bool Client::is_ssl() const { return false; } + +inline std::shared_ptr Client::Get(const char *path, + Progress progress) { + return Get(path, Headers(), progress); } -inline bool ClientImpl::is_ssl() const { return false; } - -inline Result ClientImpl::Get(const std::string &path) { - return Get(path, Headers(), Progress()); -} - -inline Result ClientImpl::Get(const std::string &path, Progress progress) { - return Get(path, Headers(), std::move(progress)); -} - -inline Result ClientImpl::Get(const std::string &path, const Headers &headers) { - return Get(path, headers, Progress()); -} - -inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - Progress progress) { +inline std::shared_ptr +Client::Get(const char *path, const Headers &headers, Progress progress) { Request req; req.method = "GET"; req.path = path; req.headers = headers; - req.progress = std::move(progress); - return send_(std::move(req)); + auto res = std::make_shared(); + res->progress = progress; + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Get(const std::string &path, - ContentReceiver content_receiver) { - return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr); +inline std::shared_ptr Client::Get(const char *path, + ContentReceiver content_receiver, + Progress progress) { + return Get(path, Headers(), content_receiver, progress); } -inline Result ClientImpl::Get(const std::string &path, - ContentReceiver content_receiver, - Progress progress) { - return Get(path, Headers(), nullptr, std::move(content_receiver), - std::move(progress)); -} - -inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver) { - return Get(path, headers, nullptr, std::move(content_receiver), nullptr); -} - -inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, - Progress progress) { - return Get(path, headers, nullptr, std::move(content_receiver), - std::move(progress)); -} - -inline Result ClientImpl::Get(const std::string &path, - ResponseHandler response_handler, - ContentReceiver content_receiver) { - return Get(path, Headers(), std::move(response_handler), - std::move(content_receiver), nullptr); -} - -inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver) { - return Get(path, headers, std::move(response_handler), - std::move(content_receiver), nullptr); -} - -inline Result ClientImpl::Get(const std::string &path, - ResponseHandler response_handler, - ContentReceiver content_receiver, - Progress progress) { - return Get(path, Headers(), std::move(response_handler), - std::move(content_receiver), std::move(progress)); -} - -inline Result ClientImpl::Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver, - Progress progress) { +inline std::shared_ptr Client::Get(const char *path, + const Headers &headers, + ContentReceiver content_receiver, + Progress progress) { Request req; req.method = "GET"; req.path = path; req.headers = headers; - req.response_handler = std::move(response_handler); - req.content_receiver = - [content_receiver](const char *data, size_t data_length, - uint64_t /*offset*/, uint64_t /*total_length*/) { - return content_receiver(data, data_length); - }; - req.progress = std::move(progress); - return send_(std::move(req)); + auto res = std::make_shared(); + res->content_receiver = content_receiver; + res->progress = progress; + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress) { - if (params.empty()) { return Get(path, headers); } - - std::string path_with_query = append_query_params(path, params); - return Get(path_with_query, headers, std::move(progress)); -} - -inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, - const Headers &headers, - ContentReceiver content_receiver, - Progress progress) { - return Get(path, params, headers, nullptr, std::move(content_receiver), - std::move(progress)); -} - -inline Result ClientImpl::Get(const std::string &path, const Params ¶ms, - const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver, - Progress progress) { - if (params.empty()) { - return Get(path, headers, std::move(response_handler), - std::move(content_receiver), std::move(progress)); - } - - std::string path_with_query = append_query_params(path, params); - return Get(path_with_query, headers, std::move(response_handler), - std::move(content_receiver), std::move(progress)); -} - -inline Result ClientImpl::Head(const std::string &path) { +inline std::shared_ptr Client::Head(const char *path) { return Head(path, Headers()); } -inline Result ClientImpl::Head(const std::string &path, - const Headers &headers) { +inline std::shared_ptr Client::Head(const char *path, + const Headers &headers) { Request req; req.method = "HEAD"; req.headers = headers; req.path = path; - return send_(std::move(req)); + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Post(const std::string &path) { - return Post(path, std::string(), std::string()); -} - -inline Result ClientImpl::Post(const std::string &path, - const Headers &headers) { - return Post(path, headers, nullptr, 0, std::string()); -} - -inline Result ClientImpl::Post(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return Post(path, Headers(), body, content_length, content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, body, content_length, - nullptr, nullptr, content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const std::string &body, - const std::string &content_type) { +inline std::shared_ptr Client::Post(const char *path, + const std::string &body, + const char *content_type) { return Post(path, Headers(), body, content_type); } -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, body.data(), - body.size(), nullptr, nullptr, - content_type); +inline std::shared_ptr Client::Post(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "POST"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Post(const std::string &path, const Params ¶ms) { +inline std::shared_ptr Client::Post(const char *path, + const Params ¶ms) { return Post(path, Headers(), params); } -inline Result ClientImpl::Post(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return Post(path, Headers(), content_length, std::move(content_provider), - content_type); -} +inline std::shared_ptr +Client::Post(const char *path, const Headers &headers, const Params ¶ms) { + std::string query; + for (auto it = params.begin(); it != params.end(); ++it) { + if (it != params.begin()) { query += "&"; } + query += it->first; + query += "="; + query += detail::encode_url(it->second); + } -inline Result ClientImpl::Post(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return Post(path, Headers(), std::move(content_provider), content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, nullptr, - content_length, std::move(content_provider), - nullptr, content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr, - std::move(content_provider), content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const Params ¶ms) { - auto query = detail::params_to_query_str(params); return Post(path, headers, query, "application/x-www-form-urlencoded"); } -inline Result ClientImpl::Post(const std::string &path, - const MultipartFormDataItems &items) { - return Post(path, Headers(), items); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { - const auto &boundary = detail::make_multipart_data_boundary(); - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Post(path, headers, body, content_type); -} - -inline Result ClientImpl::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { - if (!detail::is_multipart_boundary_chars_valid(boundary)) { - return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; - } - - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Post(path, headers, body, content_type); -} - -inline Result -ClientImpl::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - const auto &boundary = detail::make_multipart_data_boundary(); - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - return send_with_content_provider( - "POST", path, headers, nullptr, 0, nullptr, - get_multipart_content_provider(boundary, items, provider_items), - content_type); -} - -inline Result ClientImpl::Put(const std::string &path) { - return Put(path, std::string(), std::string()); -} - -inline Result ClientImpl::Put(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return Put(path, Headers(), body, content_length, content_type); -} - -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return send_with_content_provider("PUT", path, headers, body, content_length, - nullptr, nullptr, content_type); -} - -inline Result ClientImpl::Put(const std::string &path, const std::string &body, - const std::string &content_type) { +inline std::shared_ptr Client::Put(const char *path, + const std::string &body, + const char *content_type) { return Put(path, Headers(), body, content_type); } -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return send_with_content_provider("PUT", path, headers, body.data(), - body.size(), nullptr, nullptr, - content_type); +inline std::shared_ptr Client::Put(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "PUT"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Put(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return Put(path, Headers(), content_length, std::move(content_provider), - content_type); -} - -inline Result ClientImpl::Put(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return Put(path, Headers(), std::move(content_provider), content_type); -} - -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return send_with_content_provider("PUT", path, headers, nullptr, - content_length, std::move(content_provider), - nullptr, content_type); -} - -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr, - std::move(content_provider), content_type); -} - -inline Result ClientImpl::Put(const std::string &path, const Params ¶ms) { - return Put(path, Headers(), params); -} - -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const Params ¶ms) { - auto query = detail::params_to_query_str(params); - return Put(path, headers, query, "application/x-www-form-urlencoded"); -} - -inline Result ClientImpl::Put(const std::string &path, - const MultipartFormDataItems &items) { - return Put(path, Headers(), items); -} - -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { - const auto &boundary = detail::make_multipart_data_boundary(); - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Put(path, headers, body, content_type); -} - -inline Result ClientImpl::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { - if (!detail::is_multipart_boundary_chars_valid(boundary)) { - return Result{nullptr, Error::UnsupportedMultipartBoundaryChars}; - } - - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - const auto &body = detail::serialize_multipart_formdata(items, boundary); - return Put(path, headers, body, content_type); -} - -inline Result -ClientImpl::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - const auto &boundary = detail::make_multipart_data_boundary(); - const auto &content_type = - detail::serialize_multipart_formdata_get_content_type(boundary); - return send_with_content_provider( - "PUT", path, headers, nullptr, 0, nullptr, - get_multipart_content_provider(boundary, items, provider_items), - content_type); -} -inline Result ClientImpl::Patch(const std::string &path) { - return Patch(path, std::string(), std::string()); -} - -inline Result ClientImpl::Patch(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return Patch(path, Headers(), body, content_length, content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return send_with_content_provider("PATCH", path, headers, body, - content_length, nullptr, nullptr, - content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, - const std::string &body, - const std::string &content_type) { +inline std::shared_ptr Client::Patch(const char *path, + const std::string &body, + const char *content_type) { return Patch(path, Headers(), body, content_type); } -inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return send_with_content_provider("PATCH", path, headers, body.data(), - body.size(), nullptr, nullptr, - content_type); +inline std::shared_ptr Client::Patch(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { + Request req; + req.method = "PATCH"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return Patch(path, Headers(), content_length, std::move(content_provider), - content_type); +inline std::shared_ptr Client::Delete(const char *path, + const std::string &body, + const char *content_type) { + return Delete(path, Headers(), body, content_type); } -inline Result ClientImpl::Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return Patch(path, Headers(), std::move(content_provider), content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return send_with_content_provider("PATCH", path, headers, nullptr, - content_length, std::move(content_provider), - nullptr, content_type); -} - -inline Result ClientImpl::Patch(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr, - std::move(content_provider), content_type); -} - -inline Result ClientImpl::Delete(const std::string &path) { - return Delete(path, Headers(), std::string(), std::string()); -} - -inline Result ClientImpl::Delete(const std::string &path, - const Headers &headers) { - return Delete(path, headers, std::string(), std::string()); -} - -inline Result ClientImpl::Delete(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return Delete(path, Headers(), body, content_length, content_type); -} - -inline Result ClientImpl::Delete(const std::string &path, - const Headers &headers, const char *body, - size_t content_length, - const std::string &content_type) { +inline std::shared_ptr Client::Delete(const char *path, + const Headers &headers, + const std::string &body, + const char *content_type) { Request req; req.method = "DELETE"; req.headers = headers; req.path = path; - if (!content_type.empty()) { req.set_header("Content-Type", content_type); } - req.body.assign(body, content_length); + if (content_type) { req.headers.emplace("Content-Type", content_type); } + req.body = body; - return send_(std::move(req)); + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; } -inline Result ClientImpl::Delete(const std::string &path, - const std::string &body, - const std::string &content_type) { - return Delete(path, Headers(), body.data(), body.size(), content_type); -} - -inline Result ClientImpl::Delete(const std::string &path, - const Headers &headers, - const std::string &body, - const std::string &content_type) { - return Delete(path, headers, body.data(), body.size(), content_type); -} - -inline Result ClientImpl::Options(const std::string &path) { +inline std::shared_ptr Client::Options(const char *path) { return Options(path, Headers()); } -inline Result ClientImpl::Options(const std::string &path, - const Headers &headers) { +inline std::shared_ptr Client::Options(const char *path, + const Headers &headers) { Request req; req.method = "OPTIONS"; - req.headers = headers; req.path = path; + req.headers = headers; - return send_(std::move(req)); -} + auto res = std::make_shared(); -inline void ClientImpl::stop() { - std::lock_guard guard(socket_mutex_); - - // If there is anything ongoing right now, the ONLY thread-safe thing we can - // do is to shutdown_socket, so that threads using this socket suddenly - // discover they can't read/write any more and error out. Everything else - // (closing the socket, shutting ssl down) is unsafe because these actions are - // not thread-safe. - if (socket_requests_in_flight_ > 0) { - shutdown_socket(socket_); - - // Aside from that, we set a flag for the socket to be closed when we're - // done. - socket_should_be_closed_when_request_is_done_ = true; - return; - } - - // Otherwise, still holding the mutex, we can shut everything down ourselves - shutdown_ssl(socket_, true); - shutdown_socket(socket_); - close_socket(socket_); -} - -inline std::string ClientImpl::host() const { return host_; } - -inline int ClientImpl::port() const { return port_; } - -inline size_t ClientImpl::is_socket_open() const { - std::lock_guard guard(socket_mutex_); - return socket_.is_open(); -} - -inline socket_t ClientImpl::socket() const { return socket_.sock; } - -inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) { - connection_timeout_sec_ = sec; - connection_timeout_usec_ = usec; -} - -inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) { - read_timeout_sec_ = sec; - read_timeout_usec_ = usec; -} - -inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) { - write_timeout_sec_ = sec; - write_timeout_usec_ = usec; -} - -inline void ClientImpl::set_basic_auth(const std::string &username, - const std::string &password) { - basic_auth_username_ = username; - basic_auth_password_ = password; -} - -inline void ClientImpl::set_bearer_token_auth(const std::string &token) { - bearer_token_auth_token_ = token; -} - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline void ClientImpl::set_digest_auth(const std::string &username, - const std::string &password) { - digest_auth_username_ = username; - digest_auth_password_ = password; -} -#endif - -inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; } - -inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; } - -inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; } - -inline void -ClientImpl::set_hostname_addr_map(std::map addr_map) { - addr_map_ = std::move(addr_map); -} - -inline void ClientImpl::set_default_headers(Headers headers) { - default_headers_ = std::move(headers); -} - -inline void ClientImpl::set_header_writer( - std::function const &writer) { - header_writer_ = writer; -} - -inline void ClientImpl::set_address_family(int family) { - address_family_ = family; -} - -inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; } - -inline void ClientImpl::set_socket_options(SocketOptions socket_options) { - socket_options_ = std::move(socket_options); -} - -inline void ClientImpl::set_compress(bool on) { compress_ = on; } - -inline void ClientImpl::set_decompress(bool on) { decompress_ = on; } - -inline void ClientImpl::set_interface(const std::string &intf) { - interface_ = intf; -} - -inline void ClientImpl::set_proxy(const std::string &host, int port) { - proxy_host_ = host; - proxy_port_ = port; -} - -inline void ClientImpl::set_proxy_basic_auth(const std::string &username, - const std::string &password) { - proxy_basic_auth_username_ = username; - proxy_basic_auth_password_ = password; -} - -inline void ClientImpl::set_proxy_bearer_token_auth(const std::string &token) { - proxy_bearer_token_auth_token_ = token; -} - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline void ClientImpl::set_proxy_digest_auth(const std::string &username, - const std::string &password) { - proxy_digest_auth_username_ = username; - proxy_digest_auth_password_ = password; -} - -inline void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path, - const std::string &ca_cert_dir_path) { - ca_cert_file_path_ = ca_cert_file_path; - ca_cert_dir_path_ = ca_cert_dir_path; -} - -inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) { - if (ca_cert_store && ca_cert_store != ca_cert_store_) { - ca_cert_store_ = ca_cert_store; - } -} - -inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert, - std::size_t size) const { - auto mem = BIO_new_mem_buf(ca_cert, static_cast(size)); - if (!mem) { return nullptr; } - - auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr); - if (!inf) { - BIO_free_all(mem); - return nullptr; - } - - auto cts = X509_STORE_new(); - if (cts) { - for (auto i = 0; i < static_cast(sk_X509_INFO_num(inf)); i++) { - auto itmp = sk_X509_INFO_value(inf, i); - if (!itmp) { continue; } - - if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); } - if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); } - } - } - - sk_X509_INFO_pop_free(inf, X509_INFO_free); - BIO_free_all(mem); - return cts; -} - -inline void ClientImpl::enable_server_certificate_verification(bool enabled) { - server_certificate_verification_ = enabled; -} -#endif - -inline void ClientImpl::set_logger(Logger logger) { - logger_ = std::move(logger); + return send(req, *res) ? res : nullptr; } /* @@ -8215,227 +2394,129 @@ inline void ClientImpl::set_logger(Logger logger) { #ifdef CPPHTTPLIB_OPENSSL_SUPPORT namespace detail { -template -inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex, - U SSL_connect_or_accept, V setup) { +template +inline bool +read_and_close_socket_ssl(socket_t sock, size_t keep_alive_max_count, + // TODO: OpenSSL 1.0.2 occasionally crashes... + // The upcoming 1.1.0 is going to be thread safe. + SSL_CTX *ctx, std::mutex &ctx_mutex, + U SSL_connect_or_accept, V setup, T callback) { SSL *ssl = nullptr; { std::lock_guard guard(ctx_mutex); ssl = SSL_new(ctx); } - if (ssl) { - set_nonblocking(sock, true); - auto bio = BIO_new_socket(static_cast(sock), BIO_NOCLOSE); - BIO_set_nbio(bio, 1); - SSL_set_bio(ssl, bio, bio); - - if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) { - SSL_shutdown(ssl); - { - std::lock_guard guard(ctx_mutex); - SSL_free(ssl); - } - set_nonblocking(sock, false); - return nullptr; - } - BIO_set_nbio(bio, 0); - set_nonblocking(sock, false); - } - - return ssl; -} - -inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl, - bool shutdown_gracefully) { - // sometimes we may want to skip this to try to avoid SIGPIPE if we know - // the remote has closed the network connection - // Note that it is not always possible to avoid SIGPIPE, this is merely a - // best-efforts. - if (shutdown_gracefully) { SSL_shutdown(ssl); } - - std::lock_guard guard(ctx_mutex); - SSL_free(ssl); -} - -template -bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl, - U ssl_connect_or_accept, - time_t timeout_sec, - time_t timeout_usec) { - auto res = 0; - while ((res = ssl_connect_or_accept(ssl)) != 1) { - auto err = SSL_get_error(ssl, res); - switch (err) { - case SSL_ERROR_WANT_READ: - if (select_read(sock, timeout_sec, timeout_usec) > 0) { continue; } - break; - case SSL_ERROR_WANT_WRITE: - if (select_write(sock, timeout_sec, timeout_usec) > 0) { continue; } - break; - default: break; - } + if (!ssl) { + close_socket(sock); return false; } - return true; -} -template -inline bool process_server_socket_ssl( - const std::atomic &svr_sock, SSL *ssl, socket_t sock, - size_t keep_alive_max_count, time_t keep_alive_timeout_sec, - time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec, T callback) { - return process_server_socket_core( - svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec, - [&](bool close_connection, bool &connection_closed) { - SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec, - write_timeout_sec, write_timeout_usec); - return callback(strm, close_connection, connection_closed); - }); -} + auto bio = BIO_new_socket(sock, BIO_NOCLOSE); + SSL_set_bio(ssl, bio, bio); -template -inline bool -process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec, - time_t read_timeout_usec, time_t write_timeout_sec, - time_t write_timeout_usec, T callback) { - SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec, - write_timeout_sec, write_timeout_usec); - return callback(strm); + if (!setup(ssl)) { + SSL_shutdown(ssl); + { + std::lock_guard guard(ctx_mutex); + SSL_free(ssl); + } + + close_socket(sock); + return false; + } + + bool ret = false; + + if (SSL_connect_or_accept(ssl) == 1) { + if (keep_alive_max_count > 0) { + auto count = keep_alive_max_count; + while (count > 0 && + detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND, + CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0) { + SSLSocketStream strm(sock, ssl); + auto last_connection = count == 1; + auto connection_close = false; + + ret = callback(ssl, strm, last_connection, connection_close); + if (!ret || connection_close) { break; } + + count--; + } + } else { + SSLSocketStream strm(sock, ssl); + auto dummy_connection_close = false; + ret = callback(ssl, strm, true, dummy_connection_close); + } + } + + SSL_shutdown(ssl); + { + std::lock_guard guard(ctx_mutex); + SSL_free(ssl); + } + + close_socket(sock); + + return ret; } class SSLInit { public: SSLInit() { - OPENSSL_init_ssl( - OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + SSL_load_error_strings(); + SSL_library_init(); } + + ~SSLInit() { ERR_free_strings(); } }; -// SSL socket stream implementation -inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl, - time_t read_timeout_sec, - time_t read_timeout_usec, - time_t write_timeout_sec, - time_t write_timeout_usec) - : sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec), - read_timeout_usec_(read_timeout_usec), - write_timeout_sec_(write_timeout_sec), - write_timeout_usec_(write_timeout_usec) { - SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY); -} - -inline SSLSocketStream::~SSLSocketStream() = default; - -inline bool SSLSocketStream::is_readable() const { - return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0; -} - -inline bool SSLSocketStream::is_writable() const { - return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 && - is_socket_alive(sock_); -} - -inline ssize_t SSLSocketStream::read(char *ptr, size_t size) { - if (SSL_pending(ssl_) > 0) { - return SSL_read(ssl_, ptr, static_cast(size)); - } else if (is_readable()) { - auto ret = SSL_read(ssl_, ptr, static_cast(size)); - if (ret < 0) { - auto err = SSL_get_error(ssl_, ret); - auto n = 1000; -#ifdef _WIN32 - while (--n >= 0 && (err == SSL_ERROR_WANT_READ || - (err == SSL_ERROR_SYSCALL && - WSAGetLastError() == WSAETIMEDOUT))) { -#else - while (--n >= 0 && err == SSL_ERROR_WANT_READ) { -#endif - if (SSL_pending(ssl_) > 0) { - return SSL_read(ssl_, ptr, static_cast(size)); - } else if (is_readable()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - ret = SSL_read(ssl_, ptr, static_cast(size)); - if (ret >= 0) { return ret; } - err = SSL_get_error(ssl_, ret); - } else { - return -1; - } - } - } - return ret; - } - return -1; -} - -inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) { - if (is_writable()) { - auto handle_size = static_cast( - std::min(size, (std::numeric_limits::max)())); - - auto ret = SSL_write(ssl_, ptr, static_cast(handle_size)); - if (ret < 0) { - auto err = SSL_get_error(ssl_, ret); - auto n = 1000; -#ifdef _WIN32 - while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE || - (err == SSL_ERROR_SYSCALL && - WSAGetLastError() == WSAETIMEDOUT))) { -#else - while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) { -#endif - if (is_writable()) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - ret = SSL_write(ssl_, ptr, static_cast(handle_size)); - if (ret >= 0) { return ret; } - err = SSL_get_error(ssl_, ret); - } else { - return -1; - } - } - } - return ret; - } - return -1; -} - -inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip, - int &port) const { - detail::get_remote_ip_and_port(sock_, ip, port); -} - -inline void SSLSocketStream::get_local_ip_and_port(std::string &ip, - int &port) const { - detail::get_local_ip_and_port(sock_, ip, port); -} - -inline socket_t SSLSocketStream::socket() const { return sock_; } - static SSLInit sslinit_; } // namespace detail +// SSL socket stream implementation +inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl) + : sock_(sock), ssl_(ssl) {} + +inline SSLSocketStream::~SSLSocketStream() {} + +inline int SSLSocketStream::read(char *ptr, size_t size) { + if (SSL_pending(ssl_) > 0 || + detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND, + CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) { + return SSL_read(ssl_, ptr, size); + } + return -1; +} + +inline int SSLSocketStream::write(const char *ptr, size_t size) { + return SSL_write(ssl_, ptr, size); +} + +inline int SSLSocketStream::write(const char *ptr) { + return write(ptr, strlen(ptr)); +} + +inline std::string SSLSocketStream::get_remote_addr() const { + return detail::get_remote_addr(sock_); +} + // SSL HTTP server implementation inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, const char *client_ca_cert_file_path, - const char *client_ca_cert_dir_path, - const char *private_key_password) { - ctx_ = SSL_CTX_new(TLS_server_method()); + const char *client_ca_cert_dir_path) { + ctx_ = SSL_CTX_new(SSLv23_server_method()); if (ctx_) { SSL_CTX_set_options(ctx_, - SSL_OP_NO_COMPRESSION | + SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); - - // add default password callback before opening encrypted private key - if (private_key_password != nullptr && (private_key_password[0] != '\0')) { - SSL_CTX_set_default_passwd_cb_userdata( - ctx_, - reinterpret_cast(const_cast(private_key_password))); - } + // auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + // SSL_CTX_set_tmp_ecdh(ctx_, ecdh); + // EC_KEY_free(ecdh); if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != @@ -8443,46 +2524,19 @@ inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, SSL_CTX_free(ctx_); ctx_ = nullptr; } else if (client_ca_cert_file_path || client_ca_cert_dir_path) { + // if (client_ca_cert_file_path) { + // auto list = SSL_load_client_CA_file(client_ca_cert_file_path); + // SSL_CTX_set_client_CA_list(ctx_, list); + // } + SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path, client_ca_cert_dir_path); SSL_CTX_set_verify( - ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - } - } -} - -inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key, - X509_STORE *client_ca_cert_store) { - ctx_ = SSL_CTX_new(TLS_server_method()); - - if (ctx_) { - SSL_CTX_set_options(ctx_, - SSL_OP_NO_COMPRESSION | - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - - SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION); - - if (SSL_CTX_use_certificate(ctx_, cert) != 1 || - SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) { - SSL_CTX_free(ctx_); - ctx_ = nullptr; - } else if (client_ca_cert_store) { - SSL_CTX_set_cert_store(ctx_, client_ca_cert_store); - - SSL_CTX_set_verify( - ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - } - } -} - -inline SSLServer::SSLServer( - const std::function &setup_ssl_ctx_callback) { - ctx_ = SSL_CTX_new(TLS_method()); - if (ctx_) { - if (!setup_ssl_ctx_callback(*ctx_)) { - SSL_CTX_free(ctx_); - ctx_ = nullptr; + ctx_, + SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE, + nullptr); } } } @@ -8493,82 +2547,33 @@ inline SSLServer::~SSLServer() { inline bool SSLServer::is_valid() const { return ctx_; } -inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; } - -inline bool SSLServer::process_and_close_socket(socket_t sock) { - auto ssl = detail::ssl_new( - sock, ctx_, ctx_mutex_, - [&](SSL *ssl2) { - return detail::ssl_connect_or_accept_nonblocking( - sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_); - }, - [](SSL * /*ssl2*/) { return true; }); - - auto ret = false; - if (ssl) { - ret = detail::process_server_socket_ssl( - svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_, - read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, - write_timeout_usec_, - [this, ssl](Stream &strm, bool close_connection, - bool &connection_closed) { - return process_request(strm, close_connection, connection_closed, - [&](Request &req) { req.ssl = ssl; }); - }); - - // Shutdown gracefully if the result seemed successful, non-gracefully if - // the connection appeared to be closed. - const bool shutdown_gracefully = ret; - detail::ssl_delete(ctx_mutex_, ssl, shutdown_gracefully); - } - - detail::shutdown_socket(sock); - detail::close_socket(sock); - return ret; +inline bool SSLServer::read_and_close_socket(socket_t sock) { + return detail::read_and_close_socket_ssl( + sock, keep_alive_max_count_, ctx_, ctx_mutex_, SSL_accept, + [](SSL * /*ssl*/) { return true; }, + [this](SSL *ssl, Stream &strm, bool last_connection, + bool &connection_close) { + return process_request(strm, last_connection, connection_close, + [&](Request &req) { req.ssl = ssl; }); + }); } // SSL HTTP client implementation -inline SSLClient::SSLClient(const std::string &host) - : SSLClient(host, 443, std::string(), std::string()) {} - -inline SSLClient::SSLClient(const std::string &host, int port) - : SSLClient(host, port, std::string(), std::string()) {} - -inline SSLClient::SSLClient(const std::string &host, int port, - const std::string &client_cert_path, - const std::string &client_key_path) - : ClientImpl(host, port, client_cert_path, client_key_path) { - ctx_ = SSL_CTX_new(TLS_client_method()); +inline SSLClient::SSLClient(const char *host, int port, time_t timeout_sec, + const char *client_cert_path, + const char *client_key_path) + : Client(host, port, timeout_sec) { + ctx_ = SSL_CTX_new(SSLv23_client_method()); detail::split(&host_[0], &host_[host_.size()], '.', [&](const char *b, const char *e) { - host_components_.emplace_back(b, e); + host_components_.emplace_back(std::string(b, e)); }); - - if (!client_cert_path.empty() && !client_key_path.empty()) { - if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(), + if (client_cert_path && client_key_path) { + if (SSL_CTX_use_certificate_file(ctx_, client_cert_path, SSL_FILETYPE_PEM) != 1 || - SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(), - SSL_FILETYPE_PEM) != 1) { - SSL_CTX_free(ctx_); - ctx_ = nullptr; - } - } -} - -inline SSLClient::SSLClient(const std::string &host, int port, - X509 *client_cert, EVP_PKEY *client_key) - : ClientImpl(host, port) { - ctx_ = SSL_CTX_new(TLS_client_method()); - - detail::split(&host_[0], &host_[host_.size()], '.', - [&](const char *b, const char *e) { - host_components_.emplace_back(b, e); - }); - - if (client_cert != nullptr && client_key != nullptr) { - if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 || - SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) { + SSL_CTX_use_PrivateKey_file(ctx_, client_key_path, SSL_FILETYPE_PEM) != + 1) { SSL_CTX_free(ctx_); ctx_ = nullptr; } @@ -8577,230 +2582,69 @@ inline SSLClient::SSLClient(const std::string &host, int port, inline SSLClient::~SSLClient() { if (ctx_) { SSL_CTX_free(ctx_); } - // Make sure to shut down SSL since shutdown_ssl will resolve to the - // base function rather than the derived function once we get to the - // base class destructor, and won't free the SSL (causing a leak). - shutdown_ssl_impl(socket_, true); } inline bool SSLClient::is_valid() const { return ctx_; } -inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) { - if (ca_cert_store) { - if (ctx_) { - if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) { - // Free memory allocated for old cert and use new store `ca_cert_store` - SSL_CTX_set_cert_store(ctx_, ca_cert_store); - } - } else { - X509_STORE_free(ca_cert_store); - } - } +inline void SSLClient::set_ca_cert_path(const char *ca_cert_file_path, + const char *ca_cert_dir_path) { + if (ca_cert_file_path) { ca_cert_file_path_ = ca_cert_file_path; } + if (ca_cert_dir_path) { ca_cert_dir_path_ = ca_cert_dir_path; } } -inline void SSLClient::load_ca_cert_store(const char *ca_cert, - std::size_t size) { - set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size)); +inline void SSLClient::enable_server_certificate_verification(bool enabled) { + server_certificate_verification_ = enabled; } inline long SSLClient::get_openssl_verify_result() const { return verify_result_; } -inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; } +inline bool SSLClient::read_and_close_socket(socket_t sock, Request &req, + Response &res) { -inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) { - return is_valid() && ClientImpl::create_and_connect_socket(socket, error); -} + return is_valid() && + detail::read_and_close_socket_ssl( + sock, 0, ctx_, ctx_mutex_, + [&](SSL *ssl) { + if (ca_cert_file_path_.empty()) { + SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr); + } else { + if (!SSL_CTX_load_verify_locations( + ctx_, ca_cert_file_path_.c_str(), nullptr)) { + return false; + } + SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr); + } -// Assumes that socket_mutex_ is locked and that there are no requests in flight -inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res, - bool &success, Error &error) { - success = true; - Response proxy_res; - if (!detail::process_client_socket( - socket.sock, read_timeout_sec_, read_timeout_usec_, - write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) { - Request req2; - req2.method = "CONNECT"; - req2.path = host_and_port_; - return process_request(strm, req2, proxy_res, false, error); - })) { - // Thread-safe to close everything because we are assuming there are no - // requests in flight - shutdown_ssl(socket, true); - shutdown_socket(socket); - close_socket(socket); - success = false; - return false; - } + if (SSL_connect(ssl) != 1) { return false; } - if (proxy_res.status == StatusCode::ProxyAuthenticationRequired_407) { - if (!proxy_digest_auth_username_.empty() && - !proxy_digest_auth_password_.empty()) { - std::map auth; - if (detail::parse_www_authenticate(proxy_res, auth, true)) { - proxy_res = Response(); - if (!detail::process_client_socket( - socket.sock, read_timeout_sec_, read_timeout_usec_, - write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) { - Request req3; - req3.method = "CONNECT"; - req3.path = host_and_port_; - req3.headers.insert(detail::make_digest_authentication_header( - req3, auth, 1, detail::random_string(10), - proxy_digest_auth_username_, proxy_digest_auth_password_, - true)); - return process_request(strm, req3, proxy_res, false, error); - })) { - // Thread-safe to close everything because we are assuming there are - // no requests in flight - shutdown_ssl(socket, true); - shutdown_socket(socket); - close_socket(socket); - success = false; - return false; - } - } - } - } + if (server_certificate_verification_) { + verify_result_ = SSL_get_verify_result(ssl); - // If status code is not 200, proxy request is failed. - // Set error to ProxyConnection and return proxy response - // as the response of the request - if (proxy_res.status != StatusCode::OK_200) { - error = Error::ProxyConnection; - res = std::move(proxy_res); - // Thread-safe to close everything because we are assuming there are - // no requests in flight - shutdown_ssl(socket, true); - shutdown_socket(socket); - close_socket(socket); - return false; - } + if (verify_result_ != X509_V_OK) { return false; } - return true; -} + auto server_cert = SSL_get_peer_certificate(ssl); -inline bool SSLClient::load_certs() { - auto ret = true; + if (server_cert == nullptr) { return false; } - std::call_once(initialize_cert_, [&]() { - std::lock_guard guard(ctx_mutex_); - if (!ca_cert_file_path_.empty()) { - if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(), - nullptr)) { - ret = false; - } - } else if (!ca_cert_dir_path_.empty()) { - if (!SSL_CTX_load_verify_locations(ctx_, nullptr, - ca_cert_dir_path_.c_str())) { - ret = false; - } - } else { - auto loaded = false; -#ifdef _WIN32 - loaded = - detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_)); -#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__) -#if TARGET_OS_OSX - loaded = detail::load_system_certs_on_macos(SSL_CTX_get_cert_store(ctx_)); -#endif // TARGET_OS_OSX -#endif // _WIN32 - if (!loaded) { SSL_CTX_set_default_verify_paths(ctx_); } - } - }); + if (!verify_host(server_cert)) { + X509_free(server_cert); + return false; + } + X509_free(server_cert); + } - return ret; -} - -inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { - auto ssl = detail::ssl_new( - socket.sock, ctx_, ctx_mutex_, - [&](SSL *ssl2) { - if (server_certificate_verification_) { - if (!load_certs()) { - error = Error::SSLLoadingCerts; - return false; - } - SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr); - } - - if (!detail::ssl_connect_or_accept_nonblocking( - socket.sock, ssl2, SSL_connect, connection_timeout_sec_, - connection_timeout_usec_)) { - error = Error::SSLConnection; - return false; - } - - if (server_certificate_verification_) { - verify_result_ = SSL_get_verify_result(ssl2); - - if (verify_result_ != X509_V_OK) { - error = Error::SSLServerVerification; - return false; - } - - auto server_cert = SSL_get1_peer_certificate(ssl2); - - if (server_cert == nullptr) { - error = Error::SSLServerVerification; - return false; - } - - if (!verify_host(server_cert)) { - X509_free(server_cert); - error = Error::SSLServerVerification; - return false; - } - X509_free(server_cert); - } - - return true; - }, - [&](SSL *ssl2) { - // NOTE: Direct call instead of using the OpenSSL macro to suppress - // -Wold-style-cast warning - // SSL_set_tlsext_host_name(ssl2, host_.c_str()); - SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, - static_cast(const_cast(host_.c_str()))); - return true; - }); - - if (ssl) { - socket.ssl = ssl; - return true; - } - - shutdown_socket(socket); - close_socket(socket); - return false; -} - -inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) { - shutdown_ssl_impl(socket, shutdown_gracefully); -} - -inline void SSLClient::shutdown_ssl_impl(Socket &socket, - bool shutdown_gracefully) { - if (socket.sock == INVALID_SOCKET) { - assert(socket.ssl == nullptr); - return; - } - if (socket.ssl) { - detail::ssl_delete(ctx_mutex_, socket.ssl, shutdown_gracefully); - socket.ssl = nullptr; - } - assert(socket.ssl == nullptr); -} - -inline bool -SSLClient::process_socket(const Socket &socket, - std::function callback) { - assert(socket.ssl); - return detail::process_client_socket_ssl( - socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_, - write_timeout_sec_, write_timeout_usec_, std::move(callback)); + return true; + }, + [&](SSL *ssl) { + SSL_set_tlsext_host_name(ssl, host_.c_str()); + return true; + }, + [&](SSL * /*ssl*/, Stream &strm, bool /*last_connection*/, + bool &connection_close) { + return process_request(strm, req, res, connection_close); + }); } inline bool SSLClient::is_ssl() const { return true; } @@ -8837,11 +2681,10 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { auto type = GEN_DNS; - struct in6_addr addr6 {}; - struct in_addr addr {}; + struct in6_addr addr6; + struct in_addr addr; size_t addr_len = 0; -#ifndef __MINGW32__ if (inet_pton(AF_INET6, host_.c_str(), &addr6)) { type = GEN_IPADD; addr_len = sizeof(struct in6_addr); @@ -8849,42 +2692,42 @@ SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { type = GEN_IPADD; addr_len = sizeof(struct in_addr); } -#endif auto alt_names = static_cast( X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr)); if (alt_names) { auto dsn_matched = false; - auto ip_matched = false; + auto ip_mached = false; auto count = sk_GENERAL_NAME_num(alt_names); - for (decltype(count) i = 0; i < count && !dsn_matched; i++) { + for (auto i = 0; i < count && !dsn_matched; i++) { auto val = sk_GENERAL_NAME_value(alt_names, i); if (val->type == type) { - auto name = - reinterpret_cast(ASN1_STRING_get0_data(val->d.ia5)); - auto name_len = static_cast(ASN1_STRING_length(val->d.ia5)); + auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5); + auto name_len = (size_t)ASN1_STRING_length(val->d.ia5); - switch (type) { - case GEN_DNS: dsn_matched = check_host_name(name, name_len); break; + if (strlen(name) == name_len) { + switch (type) { + case GEN_DNS: dsn_matched = check_host_name(name, name_len); break; - case GEN_IPADD: - if (!memcmp(&addr6, name, addr_len) || - !memcmp(&addr, name, addr_len)) { - ip_matched = true; + case GEN_IPADD: + if (!memcmp(&addr6, name, addr_len) || + !memcmp(&addr, name, addr_len)) { + ip_mached = true; + } + break; } - break; } } } - if (dsn_matched || ip_matched) { ret = true; } + if (dsn_matched || ip_mached) { ret = true; } } - GENERAL_NAMES_free(const_cast( - reinterpret_cast(alt_names))); + GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names); + return ret; } @@ -8896,9 +2739,7 @@ inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const { auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName, name, sizeof(name)); - if (name_len != -1) { - return check_host_name(name, static_cast(name_len)); - } + if (name_len != -1) { return check_host_name(name, name_len); } } return false; @@ -8913,7 +2754,7 @@ inline bool SSLClient::check_host_name(const char *pattern, std::vector pattern_components; detail::split(&pattern[0], &pattern[pattern_len], '.', [&](const char *b, const char *e) { - pattern_components.emplace_back(b, e); + pattern_components.emplace_back(std::string(b, e)); }); if (host_components_.size() != pattern_components.size()) { return false; } @@ -8933,509 +2774,6 @@ inline bool SSLClient::check_host_name(const char *pattern, } #endif -// Universal client implementation -inline Client::Client(const std::string &scheme_host_port) - : Client(scheme_host_port, std::string(), std::string()) {} - -inline Client::Client(const std::string &scheme_host_port, - const std::string &client_cert_path, - const std::string &client_key_path) { - const static std::regex re( - R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)"); - - std::smatch m; - if (std::regex_match(scheme_host_port, m, re)) { - auto scheme = m[1].str(); - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - if (!scheme.empty() && (scheme != "http" && scheme != "https")) { -#else - if (!scheme.empty() && scheme != "http") { -#endif -#ifndef CPPHTTPLIB_NO_EXCEPTIONS - std::string msg = "'" + scheme + "' scheme is not supported."; - throw std::invalid_argument(msg); -#endif - return; - } - - auto is_ssl = scheme == "https"; - - auto host = m[2].str(); - if (host.empty()) { host = m[3].str(); } - - auto port_str = m[4].str(); - auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80); - - if (is_ssl) { -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - cli_ = detail::make_unique(host, port, client_cert_path, - client_key_path); - is_ssl_ = is_ssl; -#endif - } else { - cli_ = detail::make_unique(host, port, client_cert_path, - client_key_path); - } - } else { - cli_ = detail::make_unique(scheme_host_port, 80, - client_cert_path, client_key_path); - } -} - -inline Client::Client(const std::string &host, int port) - : cli_(detail::make_unique(host, port)) {} - -inline Client::Client(const std::string &host, int port, - const std::string &client_cert_path, - const std::string &client_key_path) - : cli_(detail::make_unique(host, port, client_cert_path, - client_key_path)) {} - -inline Client::~Client() = default; - -inline bool Client::is_valid() const { - return cli_ != nullptr && cli_->is_valid(); -} - -inline Result Client::Get(const std::string &path) { return cli_->Get(path); } -inline Result Client::Get(const std::string &path, const Headers &headers) { - return cli_->Get(path, headers); -} -inline Result Client::Get(const std::string &path, Progress progress) { - return cli_->Get(path, std::move(progress)); -} -inline Result Client::Get(const std::string &path, const Headers &headers, - Progress progress) { - return cli_->Get(path, headers, std::move(progress)); -} -inline Result Client::Get(const std::string &path, - ContentReceiver content_receiver) { - return cli_->Get(path, std::move(content_receiver)); -} -inline Result Client::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver) { - return cli_->Get(path, headers, std::move(content_receiver)); -} -inline Result Client::Get(const std::string &path, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, std::move(content_receiver), std::move(progress)); -} -inline Result Client::Get(const std::string &path, const Headers &headers, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, headers, std::move(content_receiver), - std::move(progress)); -} -inline Result Client::Get(const std::string &path, - ResponseHandler response_handler, - ContentReceiver content_receiver) { - return cli_->Get(path, std::move(response_handler), - std::move(content_receiver)); -} -inline Result Client::Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver) { - return cli_->Get(path, headers, std::move(response_handler), - std::move(content_receiver)); -} -inline Result Client::Get(const std::string &path, - ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, std::move(response_handler), - std::move(content_receiver), std::move(progress)); -} -inline Result Client::Get(const std::string &path, const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, headers, std::move(response_handler), - std::move(content_receiver), std::move(progress)); -} -inline Result Client::Get(const std::string &path, const Params ¶ms, - const Headers &headers, Progress progress) { - return cli_->Get(path, params, headers, std::move(progress)); -} -inline Result Client::Get(const std::string &path, const Params ¶ms, - const Headers &headers, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, params, headers, std::move(content_receiver), - std::move(progress)); -} -inline Result Client::Get(const std::string &path, const Params ¶ms, - const Headers &headers, - ResponseHandler response_handler, - ContentReceiver content_receiver, Progress progress) { - return cli_->Get(path, params, headers, std::move(response_handler), - std::move(content_receiver), std::move(progress)); -} - -inline Result Client::Head(const std::string &path) { return cli_->Head(path); } -inline Result Client::Head(const std::string &path, const Headers &headers) { - return cli_->Head(path, headers); -} - -inline Result Client::Post(const std::string &path) { return cli_->Post(path); } -inline Result Client::Post(const std::string &path, const Headers &headers) { - return cli_->Post(path, headers); -} -inline Result Client::Post(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return cli_->Post(path, body, content_length, content_type); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Post(path, headers, body, content_length, content_type); -} -inline Result Client::Post(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Post(path, body, content_type); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return cli_->Post(path, headers, body, content_type); -} -inline Result Client::Post(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return cli_->Post(path, content_length, std::move(content_provider), - content_type); -} -inline Result Client::Post(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Post(path, std::move(content_provider), content_type); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return cli_->Post(path, headers, content_length, std::move(content_provider), - content_type); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Post(path, headers, std::move(content_provider), content_type); -} -inline Result Client::Post(const std::string &path, const Params ¶ms) { - return cli_->Post(path, params); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - const Params ¶ms) { - return cli_->Post(path, headers, params); -} -inline Result Client::Post(const std::string &path, - const MultipartFormDataItems &items) { - return cli_->Post(path, items); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { - return cli_->Post(path, headers, items); -} -inline Result Client::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { - return cli_->Post(path, headers, items, boundary); -} -inline Result -Client::Post(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - return cli_->Post(path, headers, items, provider_items); -} -inline Result Client::Put(const std::string &path) { return cli_->Put(path); } -inline Result Client::Put(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return cli_->Put(path, body, content_length, content_type); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Put(path, headers, body, content_length, content_type); -} -inline Result Client::Put(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Put(path, body, content_type); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return cli_->Put(path, headers, body, content_type); -} -inline Result Client::Put(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return cli_->Put(path, content_length, std::move(content_provider), - content_type); -} -inline Result Client::Put(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Put(path, std::move(content_provider), content_type); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return cli_->Put(path, headers, content_length, std::move(content_provider), - content_type); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Put(path, headers, std::move(content_provider), content_type); -} -inline Result Client::Put(const std::string &path, const Params ¶ms) { - return cli_->Put(path, params); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - const Params ¶ms) { - return cli_->Put(path, headers, params); -} -inline Result Client::Put(const std::string &path, - const MultipartFormDataItems &items) { - return cli_->Put(path, items); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items) { - return cli_->Put(path, headers, items); -} -inline Result Client::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string &boundary) { - return cli_->Put(path, headers, items, boundary); -} -inline Result -Client::Put(const std::string &path, const Headers &headers, - const MultipartFormDataItems &items, - const MultipartFormDataProviderItems &provider_items) { - return cli_->Put(path, headers, items, provider_items); -} -inline Result Client::Patch(const std::string &path) { - return cli_->Patch(path); -} -inline Result Client::Patch(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return cli_->Patch(path, body, content_length, content_type); -} -inline Result Client::Patch(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Patch(path, headers, body, content_length, content_type); -} -inline Result Client::Patch(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Patch(path, body, content_type); -} -inline Result Client::Patch(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return cli_->Patch(path, headers, body, content_type); -} -inline Result Client::Patch(const std::string &path, size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return cli_->Patch(path, content_length, std::move(content_provider), - content_type); -} -inline Result Client::Patch(const std::string &path, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Patch(path, std::move(content_provider), content_type); -} -inline Result Client::Patch(const std::string &path, const Headers &headers, - size_t content_length, - ContentProvider content_provider, - const std::string &content_type) { - return cli_->Patch(path, headers, content_length, std::move(content_provider), - content_type); -} -inline Result Client::Patch(const std::string &path, const Headers &headers, - ContentProviderWithoutLength content_provider, - const std::string &content_type) { - return cli_->Patch(path, headers, std::move(content_provider), content_type); -} -inline Result Client::Delete(const std::string &path) { - return cli_->Delete(path); -} -inline Result Client::Delete(const std::string &path, const Headers &headers) { - return cli_->Delete(path, headers); -} -inline Result Client::Delete(const std::string &path, const char *body, - size_t content_length, - const std::string &content_type) { - return cli_->Delete(path, body, content_length, content_type); -} -inline Result Client::Delete(const std::string &path, const Headers &headers, - const char *body, size_t content_length, - const std::string &content_type) { - return cli_->Delete(path, headers, body, content_length, content_type); -} -inline Result Client::Delete(const std::string &path, const std::string &body, - const std::string &content_type) { - return cli_->Delete(path, body, content_type); -} -inline Result Client::Delete(const std::string &path, const Headers &headers, - const std::string &body, - const std::string &content_type) { - return cli_->Delete(path, headers, body, content_type); -} -inline Result Client::Options(const std::string &path) { - return cli_->Options(path); -} -inline Result Client::Options(const std::string &path, const Headers &headers) { - return cli_->Options(path, headers); -} - -inline bool Client::send(Request &req, Response &res, Error &error) { - return cli_->send(req, res, error); -} - -inline Result Client::send(const Request &req) { return cli_->send(req); } - -inline void Client::stop() { cli_->stop(); } - -inline std::string Client::host() const { return cli_->host(); } - -inline int Client::port() const { return cli_->port(); } - -inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); } - -inline socket_t Client::socket() const { return cli_->socket(); } - -inline void -Client::set_hostname_addr_map(std::map addr_map) { - cli_->set_hostname_addr_map(std::move(addr_map)); -} - -inline void Client::set_default_headers(Headers headers) { - cli_->set_default_headers(std::move(headers)); -} - -inline void Client::set_header_writer( - std::function const &writer) { - cli_->set_header_writer(writer); -} - -inline void Client::set_address_family(int family) { - cli_->set_address_family(family); -} - -inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); } - -inline void Client::set_socket_options(SocketOptions socket_options) { - cli_->set_socket_options(std::move(socket_options)); -} - -inline void Client::set_connection_timeout(time_t sec, time_t usec) { - cli_->set_connection_timeout(sec, usec); -} - -inline void Client::set_read_timeout(time_t sec, time_t usec) { - cli_->set_read_timeout(sec, usec); -} - -inline void Client::set_write_timeout(time_t sec, time_t usec) { - cli_->set_write_timeout(sec, usec); -} - -inline void Client::set_basic_auth(const std::string &username, - const std::string &password) { - cli_->set_basic_auth(username, password); -} -inline void Client::set_bearer_token_auth(const std::string &token) { - cli_->set_bearer_token_auth(token); -} -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline void Client::set_digest_auth(const std::string &username, - const std::string &password) { - cli_->set_digest_auth(username, password); -} -#endif - -inline void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); } -inline void Client::set_follow_location(bool on) { - cli_->set_follow_location(on); -} - -inline void Client::set_url_encode(bool on) { cli_->set_url_encode(on); } - -inline void Client::set_compress(bool on) { cli_->set_compress(on); } - -inline void Client::set_decompress(bool on) { cli_->set_decompress(on); } - -inline void Client::set_interface(const std::string &intf) { - cli_->set_interface(intf); -} - -inline void Client::set_proxy(const std::string &host, int port) { - cli_->set_proxy(host, port); -} -inline void Client::set_proxy_basic_auth(const std::string &username, - const std::string &password) { - cli_->set_proxy_basic_auth(username, password); -} -inline void Client::set_proxy_bearer_token_auth(const std::string &token) { - cli_->set_proxy_bearer_token_auth(token); -} -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline void Client::set_proxy_digest_auth(const std::string &username, - const std::string &password) { - cli_->set_proxy_digest_auth(username, password); -} -#endif - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline void Client::enable_server_certificate_verification(bool enabled) { - cli_->enable_server_certificate_verification(enabled); -} -#endif - -inline void Client::set_logger(Logger logger) { - cli_->set_logger(std::move(logger)); -} - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path, - const std::string &ca_cert_dir_path) { - cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path); -} - -inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) { - if (is_ssl_) { - static_cast(*cli_).set_ca_cert_store(ca_cert_store); - } else { - cli_->set_ca_cert_store(ca_cert_store); - } -} - -inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) { - set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size)); -} - -inline long Client::get_openssl_verify_result() const { - if (is_ssl_) { - return static_cast(*cli_).get_openssl_verify_result(); - } - return -1; // NOTE: -1 doesn't match any of X509_V_ERR_??? -} - -inline SSL_CTX *Client::ssl_context() const { - if (is_ssl_) { return static_cast(*cli_).ssl_context(); } - return nullptr; -} -#endif - -// ---------------------------------------------------------------------------- - } // namespace httplib -#if defined(_WIN32) && defined(CPPHTTPLIB_USE_POLL) -#undef poll -#endif - #endif // CPPHTTPLIB_HTTPLIB_H diff --git a/ext/ed25519-amd64-asm/batch.c b/ext/ed25519-amd64-asm/batch.c deleted file mode 100644 index 955392ea..00000000 --- a/ext/ed25519-amd64-asm/batch.c +++ /dev/null @@ -1,94 +0,0 @@ -#include "crypto_sign.h" - -#include "crypto_verify_32.h" -#include "crypto_hash_sha512.h" -#include "randombytes.h" - -#include "ge25519.h" -#include "hram.h" - -#define MAXBATCH 64 - -int crypto_sign_open_batch( - unsigned char* const m[],unsigned long long mlen[], - unsigned char* const sm[],const unsigned long long smlen[], - unsigned char* const pk[], - unsigned long long num - ) -{ - int ret = 0; - unsigned long long i, j; - shortsc25519 r[MAXBATCH]; - sc25519 scalars[2*MAXBATCH+1]; - ge25519 points[2*MAXBATCH+1]; - unsigned char hram[crypto_hash_sha512_BYTES]; - unsigned long long batchsize; - - for (i = 0;i < num;++i) mlen[i] = -1; - - while (num >= 3) { - batchsize = num; - if (batchsize > MAXBATCH) batchsize = MAXBATCH; - - for (i = 0;i < batchsize;++i) - if (smlen[i] < 64) goto fallback; - - randombytes((unsigned char*)r,sizeof(shortsc25519) * batchsize); - - /* Computing scalars[0] = ((r1s1 + r2s2 + ...)) */ - for(i=0;icaller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: tp_stack = tp -# asm 1: movq tp_stack=stack64#8 -# asm 2: movq tp_stack=56(%rsp) -movq %rdi,56(%rsp) - -# qhasm: pos *= 768 -# asm 1: imulq $768,pos=int64#1 -# asm 2: imulq $768,pos=%rdi -imulq $768,%rsi,%rdi - -# qhasm: mask = b -# asm 1: mov mask=int64#2 -# asm 2: mov mask=%rsi -mov %rdx,%rsi - -# qhasm: (int64) mask >>= 7 -# asm 1: sar $7,u=int64#5 -# asm 2: mov u=%r8 -mov %rdx,%r8 - -# qhasm: u += mask -# asm 1: add tysubx0=int64#2 -# asm 2: mov $1,>tysubx0=%rsi -mov $1,%rsi - -# qhasm: tysubx1 = 0 -# asm 1: mov $0,>tysubx1=int64#6 -# asm 2: mov $0,>tysubx1=%r9 -mov $0,%r9 - -# qhasm: tysubx2 = 0 -# asm 1: mov $0,>tysubx2=int64#7 -# asm 2: mov $0,>tysubx2=%rax -mov $0,%rax - -# qhasm: tysubx3 = 0 -# asm 1: mov $0,>tysubx3=int64#8 -# asm 2: mov $0,>tysubx3=%r10 -mov $0,%r10 - -# qhasm: txaddy0 = 1 -# asm 1: mov $1,>txaddy0=int64#9 -# asm 2: mov $1,>txaddy0=%r11 -mov $1,%r11 - -# qhasm: txaddy1 = 0 -# asm 1: mov $0,>txaddy1=int64#10 -# asm 2: mov $0,>txaddy1=%r12 -mov $0,%r12 - -# qhasm: txaddy2 = 0 -# asm 1: mov $0,>txaddy2=int64#11 -# asm 2: mov $0,>txaddy2=%r13 -mov $0,%r13 - -# qhasm: txaddy3 = 0 -# asm 1: mov $0,>txaddy3=int64#12 -# asm 2: mov $0,>txaddy3=%r14 -mov $0,%r14 - -# qhasm: =? u - 1 -# asm 1: cmp $1,t=int64#13 -# asm 2: movq 0(t=%r15 -movq 0(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 8(t=%r15 -movq 8(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 16(t=%r15 -movq 16(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 24(t=%r15 -movq 24(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 32(t=%r15 -movq 32(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 40(t=%r15 -movq 40(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 48(t=%r15 -movq 48(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 56(t=%r15 -movq 56(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 96(t=%r15 -movq 96(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 104(t=%r15 -movq 104(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 112(t=%r15 -movq 112(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 120(t=%r15 -movq 120(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 128(t=%r15 -movq 128(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 136(t=%r15 -movq 136(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 144(t=%r15 -movq 144(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 152(t=%r15 -movq 152(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 192(t=%r15 -movq 192(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 200(t=%r15 -movq 200(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 208(t=%r15 -movq 208(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 216(t=%r15 -movq 216(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 224(t=%r15 -movq 224(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 232(t=%r15 -movq 232(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 240(t=%r15 -movq 240(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 248(t=%r15 -movq 248(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 288(t=%r15 -movq 288(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 296(t=%r15 -movq 296(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 304(t=%r15 -movq 304(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 312(t=%r15 -movq 312(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 320(t=%r15 -movq 320(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 328(t=%r15 -movq 328(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 336(t=%r15 -movq 336(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 344(t=%r15 -movq 344(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 384(t=%r15 -movq 384(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 392(t=%r15 -movq 392(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 400(t=%r15 -movq 400(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 408(t=%r15 -movq 408(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 416(t=%r15 -movq 416(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 424(t=%r15 -movq 424(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 432(t=%r15 -movq 432(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 440(t=%r15 -movq 440(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 480(t=%r15 -movq 480(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 488(t=%r15 -movq 488(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 496(t=%r15 -movq 496(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 504(t=%r15 -movq 504(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 512(t=%r15 -movq 512(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 520(t=%r15 -movq 520(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 528(t=%r15 -movq 528(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 536(t=%r15 -movq 536(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 576(t=%r15 -movq 576(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 584(t=%r15 -movq 584(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 592(t=%r15 -movq 592(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 600(t=%r15 -movq 600(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 608(t=%r15 -movq 608(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 616(t=%r15 -movq 616(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 624(t=%r15 -movq 624(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 632(t=%r15 -movq 632(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 672(t=%r15 -movq 672(%rcx,%rdi),%r15 - -# qhasm: tysubx0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 680(t=%r15 -movq 680(%rcx,%rdi),%r15 - -# qhasm: tysubx1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 688(t=%r15 -movq 688(%rcx,%rdi),%r15 - -# qhasm: tysubx2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 696(t=%r15 -movq 696(%rcx,%rdi),%r15 - -# qhasm: tysubx3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 704(t=%r15 -movq 704(%rcx,%rdi),%r15 - -# qhasm: txaddy0 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 712(t=%r15 -movq 712(%rcx,%rdi),%r15 - -# qhasm: txaddy1 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 720(t=%r15 -movq 720(%rcx,%rdi),%r15 - -# qhasm: txaddy2 = t if = -# asm 1: cmove t=int64#13 -# asm 2: movq 728(t=%r15 -movq 728(%rcx,%rdi),%r15 - -# qhasm: txaddy3 = t if = -# asm 1: cmove t=int64#13 -# asm 2: mov t=%r15 -mov %rsi,%r15 - -# qhasm: tysubx0 = txaddy0 if signed< -# asm 1: cmovl t=int64#13 -# asm 2: mov t=%r15 -mov %r9,%r15 - -# qhasm: tysubx1 = txaddy1 if signed< -# asm 1: cmovl t=int64#13 -# asm 2: mov t=%r15 -mov %rax,%r15 - -# qhasm: tysubx2 = txaddy2 if signed< -# asm 1: cmovl t=int64#13 -# asm 2: mov t=%r15 -mov %r10,%r15 - -# qhasm: tysubx3 = txaddy3 if signed< -# asm 1: cmovl tp=int64#13 -# asm 2: movq tp=%r15 -movq 56(%rsp),%r15 - -# qhasm: *(uint64 *)(tp + 0) = tysubx0 -# asm 1: movq tt2d0=int64#2 -# asm 2: mov $0,>tt2d0=%rsi -mov $0,%rsi - -# qhasm: tt2d1 = 0 -# asm 1: mov $0,>tt2d1=int64#6 -# asm 2: mov $0,>tt2d1=%r9 -mov $0,%r9 - -# qhasm: tt2d2 = 0 -# asm 1: mov $0,>tt2d2=int64#7 -# asm 2: mov $0,>tt2d2=%rax -mov $0,%rax - -# qhasm: tt2d3 = 0 -# asm 1: mov $0,>tt2d3=int64#8 -# asm 2: mov $0,>tt2d3=%r10 -mov $0,%r10 - -# qhasm: =? u - 1 -# asm 1: cmp $1,t=int64#9 -# asm 2: movq 64(t=%r11 -movq 64(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 72(t=%r11 -movq 72(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 80(t=%r11 -movq 80(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 88(t=%r11 -movq 88(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 160(t=%r11 -movq 160(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 168(t=%r11 -movq 168(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 176(t=%r11 -movq 176(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 184(t=%r11 -movq 184(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 256(t=%r11 -movq 256(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 264(t=%r11 -movq 264(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 272(t=%r11 -movq 272(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 280(t=%r11 -movq 280(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 352(t=%r11 -movq 352(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 360(t=%r11 -movq 360(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 368(t=%r11 -movq 368(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 376(t=%r11 -movq 376(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 448(t=%r11 -movq 448(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 456(t=%r11 -movq 456(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 464(t=%r11 -movq 464(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 472(t=%r11 -movq 472(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 544(t=%r11 -movq 544(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 552(t=%r11 -movq 552(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 560(t=%r11 -movq 560(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 568(t=%r11 -movq 568(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 640(t=%r11 -movq 640(%rcx,%rdi),%r11 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 648(t=%r11 -movq 648(%rcx,%rdi),%r11 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 656(t=%r11 -movq 656(%rcx,%rdi),%r11 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#9 -# asm 2: movq 664(t=%r11 -movq 664(%rcx,%rdi),%r11 - -# qhasm: tt2d3 = t if = -# asm 1: cmove t=int64#5 -# asm 2: movq 736(t=%r8 -movq 736(%rcx,%rdi),%r8 - -# qhasm: tt2d0 = t if = -# asm 1: cmove t=int64#5 -# asm 2: movq 744(t=%r8 -movq 744(%rcx,%rdi),%r8 - -# qhasm: tt2d1 = t if = -# asm 1: cmove t=int64#5 -# asm 2: movq 752(t=%r8 -movq 752(%rcx,%rdi),%r8 - -# qhasm: tt2d2 = t if = -# asm 1: cmove t=int64#1 -# asm 2: movq 760(t=%rdi -movq 760(%rcx,%rdi),%rdi - -# qhasm: tt2d3 = t if = -# asm 1: cmove tt0=int64#1 -# asm 2: mov $0,>tt0=%rdi -mov $0,%rdi - -# qhasm: tt1 = 0 -# asm 1: mov $0,>tt1=int64#4 -# asm 2: mov $0,>tt1=%rcx -mov $0,%rcx - -# qhasm: tt2 = 0 -# asm 1: mov $0,>tt2=int64#5 -# asm 2: mov $0,>tt2=%r8 -mov $0,%r8 - -# qhasm: tt3 = 0 -# asm 1: mov $0,>tt3=int64#9 -# asm 2: mov $0,>tt3=%r11 -mov $0,%r11 - -# qhasm: carry? tt0 -= tt2d0 -# asm 1: sub subt0=int64#10 -# asm 2: mov $0,>subt0=%r12 -mov $0,%r12 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#11 -# asm 2: mov $38,>subt1=%r13 -mov $38,%r13 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/consts.s b/ext/ed25519-amd64-asm/consts.s deleted file mode 100644 index c272383f..00000000 --- a/ext/ed25519-amd64-asm/consts.s +++ /dev/null @@ -1,39 +0,0 @@ -.data - -.globl crypto_sign_ed25519_amd64_64_121666 -.globl crypto_sign_ed25519_amd64_64_MU0 -.globl crypto_sign_ed25519_amd64_64_MU1 -.globl crypto_sign_ed25519_amd64_64_MU2 -.globl crypto_sign_ed25519_amd64_64_MU3 -.globl crypto_sign_ed25519_amd64_64_MU4 -.globl crypto_sign_ed25519_amd64_64_ORDER0 -.globl crypto_sign_ed25519_amd64_64_ORDER1 -.globl crypto_sign_ed25519_amd64_64_ORDER2 -.globl crypto_sign_ed25519_amd64_64_ORDER3 -.globl crypto_sign_ed25519_amd64_64_EC2D0 -.globl crypto_sign_ed25519_amd64_64_EC2D1 -.globl crypto_sign_ed25519_amd64_64_EC2D2 -.globl crypto_sign_ed25519_amd64_64_EC2D3 -.globl crypto_sign_ed25519_amd64_64_38 - -.p2align 4 - -crypto_sign_ed25519_amd64_64_121666: .quad 121666 - -crypto_sign_ed25519_amd64_64_MU0: .quad 0xED9CE5A30A2C131B -crypto_sign_ed25519_amd64_64_MU1: .quad 0x2106215D086329A7 -crypto_sign_ed25519_amd64_64_MU2: .quad 0xFFFFFFFFFFFFFFEB -crypto_sign_ed25519_amd64_64_MU3: .quad 0xFFFFFFFFFFFFFFFF -crypto_sign_ed25519_amd64_64_MU4: .quad 0x000000000000000F - -crypto_sign_ed25519_amd64_64_ORDER0: .quad 0x5812631A5CF5D3ED -crypto_sign_ed25519_amd64_64_ORDER1: .quad 0x14DEF9DEA2F79CD6 -crypto_sign_ed25519_amd64_64_ORDER2: .quad 0x0000000000000000 -crypto_sign_ed25519_amd64_64_ORDER3: .quad 0x1000000000000000 - -crypto_sign_ed25519_amd64_64_EC2D0: .quad 0xEBD69B9426B2F146 -crypto_sign_ed25519_amd64_64_EC2D1: .quad 0x00E0149A8283B156 -crypto_sign_ed25519_amd64_64_EC2D2: .quad 0x198E80F2EEF3D130 -crypto_sign_ed25519_amd64_64_EC2D3: .quad 0xA406D9DC56DFFCE7 - -crypto_sign_ed25519_amd64_64_38: .quad 38 diff --git a/ext/ed25519-amd64-asm/fe25519.h b/ext/ed25519-amd64-asm/fe25519.h deleted file mode 100644 index 33ffabbe..00000000 --- a/ext/ed25519-amd64-asm/fe25519.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef FE25519_H -#define FE25519_H - -#define fe25519 crypto_sign_ed25519_amd64_64_fe25519 -#define fe25519_freeze crypto_sign_ed25519_amd64_64_fe25519_freeze -#define fe25519_unpack crypto_sign_ed25519_amd64_64_fe25519_unpack -#define fe25519_pack crypto_sign_ed25519_amd64_64_fe25519_pack -#define fe25519_iszero_vartime crypto_sign_ed25519_amd64_64_fe25519_iszero_vartime -#define fe25519_iseq_vartime crypto_sign_ed25519_amd64_64_fe25519_iseq_vartime -#define fe25519_cmov crypto_sign_ed25519_amd64_64_fe25519_cmov -#define fe25519_setint crypto_sign_ed25519_amd64_64_fe25519_setint -#define fe25519_neg crypto_sign_ed25519_amd64_64_fe25519_neg -#define fe25519_getparity crypto_sign_ed25519_amd64_64_fe25519_getparity -#define fe25519_add crypto_sign_ed25519_amd64_64_fe25519_add -#define fe25519_sub crypto_sign_ed25519_amd64_64_fe25519_sub -#define fe25519_mul crypto_sign_ed25519_amd64_64_fe25519_mul -#define fe25519_mul121666 crypto_sign_ed25519_amd64_64_fe25519_mul121666 -#define fe25519_square crypto_sign_ed25519_amd64_64_fe25519_square -#define fe25519_invert crypto_sign_ed25519_amd64_64_fe25519_invert -#define fe25519_pow2523 crypto_sign_ed25519_amd64_64_fe25519_pow2523 - -typedef struct -{ - unsigned long long v[4]; -} -fe25519; - -void fe25519_freeze(fe25519 *r); - -void fe25519_unpack(fe25519 *r, const unsigned char x[32]); - -void fe25519_pack(unsigned char r[32], const fe25519 *x); - -void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b); - -void fe25519_cswap(fe25519 *r, fe25519 *x, unsigned char b); - -void fe25519_setint(fe25519 *r, unsigned int v); - -void fe25519_neg(fe25519 *r, const fe25519 *x); - -unsigned char fe25519_getparity(const fe25519 *x); - -int fe25519_iszero_vartime(const fe25519 *x); - -int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y); - -void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y); - -void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y); - -void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y); - -void fe25519_mul121666(fe25519 *r, const fe25519 *x); - -void fe25519_square(fe25519 *r, const fe25519 *x); - -void fe25519_pow(fe25519 *r, const fe25519 *x, const unsigned char *e); - -void fe25519_invert(fe25519 *r, const fe25519 *x); - -void fe25519_pow2523(fe25519 *r, const fe25519 *x); - -#endif diff --git a/ext/ed25519-amd64-asm/fe25519_add.s b/ext/ed25519-amd64-asm/fe25519_add.s deleted file mode 100644 index b2e56252..00000000 --- a/ext/ed25519-amd64-asm/fe25519_add.s +++ /dev/null @@ -1,189 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 addt0 - -# qhasm: int64 addt1 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_add -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_fe25519_add -.globl crypto_sign_ed25519_amd64_64_fe25519_add -_crypto_sign_ed25519_amd64_64_fe25519_add: -crypto_sign_ed25519_amd64_64_fe25519_add: -mov %rsp,%r11 -and $31,%r11 -add $0,%r11 -sub %r11,%rsp - -# qhasm: r0 = *(uint64 *)(xp + 0) -# asm 1: movq 0(r0=int64#4 -# asm 2: movq 0(r0=%rcx -movq 0(%rsi),%rcx - -# qhasm: r1 = *(uint64 *)(xp + 8) -# asm 1: movq 8(r1=int64#5 -# asm 2: movq 8(r1=%r8 -movq 8(%rsi),%r8 - -# qhasm: r2 = *(uint64 *)(xp + 16) -# asm 1: movq 16(r2=int64#6 -# asm 2: movq 16(r2=%r9 -movq 16(%rsi),%r9 - -# qhasm: r3 = *(uint64 *)(xp + 24) -# asm 1: movq 24(r3=int64#2 -# asm 2: movq 24(r3=%rsi -movq 24(%rsi),%rsi - -# qhasm: carry? r0 += *(uint64 *)(yp + 0) -# asm 1: addq 0(addt0=int64#3 -# asm 2: mov $0,>addt0=%rdx -mov $0,%rdx - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#7 -# asm 2: mov $38,>addt1=%rax -mov $38,%rax - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: r0 = *(uint64 *) (rp + 0) -# asm 1: movq 0(r0=int64#2 -# asm 2: movq 0(r0=%rsi -movq 0(%rdi),%rsi - -# qhasm: r1 = *(uint64 *) (rp + 8) -# asm 1: movq 8(r1=int64#3 -# asm 2: movq 8(r1=%rdx -movq 8(%rdi),%rdx - -# qhasm: r2 = *(uint64 *) (rp + 16) -# asm 1: movq 16(r2=int64#4 -# asm 2: movq 16(r2=%rcx -movq 16(%rdi),%rcx - -# qhasm: r3 = *(uint64 *) (rp + 24) -# asm 1: movq 24(r3=int64#5 -# asm 2: movq 24(r3=%r8 -movq 24(%rdi),%r8 - -# qhasm: t0 = r0 -# asm 1: mov t0=int64#6 -# asm 2: mov t0=%r9 -mov %rsi,%r9 - -# qhasm: t1 = r1 -# asm 1: mov t1=int64#7 -# asm 2: mov t1=%rax -mov %rdx,%rax - -# qhasm: t2 = r2 -# asm 1: mov t2=int64#8 -# asm 2: mov t2=%r10 -mov %rcx,%r10 - -# qhasm: t3 = r3 -# asm 1: mov t3=int64#9 -# asm 2: mov t3=%r11 -mov %r8,%r11 - -# qhasm: two63 = 1 -# asm 1: mov $1,>two63=int64#10 -# asm 2: mov $1,>two63=%r12 -mov $1,%r12 - -# qhasm: two63 <<= 63 -# asm 1: shl $63,t0=int64#6 -# asm 2: mov t0=%r9 -mov %rsi,%r9 - -# qhasm: t1 = r1 -# asm 1: mov t1=int64#7 -# asm 2: mov t1=%rax -mov %rdx,%rax - -# qhasm: t2 = r2 -# asm 1: mov t2=int64#8 -# asm 2: mov t2=%r10 -mov %rcx,%r10 - -# qhasm: t3 = r3 -# asm 1: mov t3=int64#9 -# asm 2: mov t3=%r11 -mov %r8,%r11 - -# qhasm: carry? t0 += 19 -# asm 1: add $19,caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/fe25519_getparity.c b/ext/ed25519-amd64-asm/fe25519_getparity.c deleted file mode 100644 index a003ec8f..00000000 --- a/ext/ed25519-amd64-asm/fe25519_getparity.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "fe25519.h" - -unsigned char fe25519_getparity(const fe25519 *x) -{ - fe25519 t = *x; - fe25519_freeze(&t); - return (unsigned char)t.v[0] & 1; -} diff --git a/ext/ed25519-amd64-asm/fe25519_invert.c b/ext/ed25519-amd64-asm/fe25519_invert.c deleted file mode 100644 index a46d141f..00000000 --- a/ext/ed25519-amd64-asm/fe25519_invert.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "fe25519.h" - -void fe25519_invert(fe25519 *r, const fe25519 *x) -{ - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t,&z2); - /* 8 */ fe25519_square(&t,&t); - /* 9 */ fe25519_mul(&z9,&t,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); - /* 2^20 - 2^10 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); - /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); - /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } - /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t,&t); - /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); - /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); - /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } - /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t,&t); - /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t,&t); - /* 2^252 - 2^2 */ fe25519_square(&t,&t); - /* 2^253 - 2^3 */ fe25519_square(&t,&t); - - /* 2^254 - 2^4 */ fe25519_square(&t,&t); - - /* 2^255 - 2^5 */ fe25519_square(&t,&t); - /* 2^255 - 21 */ fe25519_mul(r,&t,&z11); -} diff --git a/ext/ed25519-amd64-asm/fe25519_iseq.c b/ext/ed25519-amd64-asm/fe25519_iseq.c deleted file mode 100644 index bf72f8c9..00000000 --- a/ext/ed25519-amd64-asm/fe25519_iseq.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "fe25519.h" - -int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y) -{ - fe25519 t1 = *x; - fe25519 t2 = *y; - fe25519_freeze(&t1); - fe25519_freeze(&t2); - if(t1.v[0] != t2.v[0]) return 0; - if(t1.v[1] != t2.v[1]) return 0; - if(t1.v[2] != t2.v[2]) return 0; - if(t1.v[3] != t2.v[3]) return 0; - return 1; -} diff --git a/ext/ed25519-amd64-asm/fe25519_iszero.c b/ext/ed25519-amd64-asm/fe25519_iszero.c deleted file mode 100644 index 99e4dafa..00000000 --- a/ext/ed25519-amd64-asm/fe25519_iszero.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "fe25519.h" - -int fe25519_iszero_vartime(const fe25519 *x) -{ - fe25519 t = *x; - fe25519_freeze(&t); - if (t.v[0]) return 0; - if (t.v[1]) return 0; - if (t.v[2]) return 0; - if (t.v[3]) return 0; - return 1; -} diff --git a/ext/ed25519-amd64-asm/fe25519_mul.s b/ext/ed25519-amd64-asm/fe25519_mul.s deleted file mode 100644 index 14784281..00000000 --- a/ext/ed25519-amd64-asm/fe25519_mul.s +++ /dev/null @@ -1,865 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_mul -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_fe25519_mul -.globl crypto_sign_ed25519_amd64_64_fe25519_mul -_crypto_sign_ed25519_amd64_64_fe25519_mul: -crypto_sign_ed25519_amd64_64_fe25519_mul: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: yp = yp -# asm 1: mov yp=int64#4 -# asm 2: mov yp=%rcx -mov %rdx,%rcx - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = *(uint64 *)(xp + 0) -# asm 1: movq 0(mulx0=int64#10 -# asm 2: movq 0(mulx0=%r12 -movq 0(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(yp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul r0=int64#11 -# asm 2: mov r0=%r13 -mov %rax,%r13 - -# qhasm: r1 = mulrdx -# asm 1: mov r1=int64#12 -# asm 2: mov r1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(yp + 8) -# asm 1: movq 8(mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul r2=int64#13 -# asm 2: mov $0,>r2=%r15 -mov $0,%r15 - -# qhasm: r2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul r3=int64#14 -# asm 2: mov $0,>r3=%rbx -mov $0,%rbx - -# qhasm: r3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq 8(mulx1=%r12 -movq 8(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(yp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq 16(mulx2=%r12 -movq 16(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(yp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#2 -# asm 2: movq 24(mulx3=%rsi -movq 24(%rsi),%rsi - -# qhasm: mulrax = *(uint64 *)(yp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? r0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: r0 += mulzero -# asm 1: add caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/fe25519_neg.c b/ext/ed25519-amd64-asm/fe25519_neg.c deleted file mode 100644 index 235b209d..00000000 --- a/ext/ed25519-amd64-asm/fe25519_neg.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "fe25519.h" - -void fe25519_neg(fe25519 *r, const fe25519 *x) -{ - fe25519 t; - fe25519_setint(&t,0); - fe25519_sub(r,&t,x); -} diff --git a/ext/ed25519-amd64-asm/fe25519_pack.c b/ext/ed25519-amd64-asm/fe25519_pack.c deleted file mode 100644 index caf51853..00000000 --- a/ext/ed25519-amd64-asm/fe25519_pack.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "fe25519.h" - -/* Assumes input x being reduced below 2^255 */ -void fe25519_pack(unsigned char r[32], const fe25519 *x) -{ - int i; - fe25519 t; - t = *x; - fe25519_freeze(&t); - /* assuming little-endian */ - for(i=0;i<32;i++) r[i] = i[(unsigned char *)&t.v]; -} - diff --git a/ext/ed25519-amd64-asm/fe25519_pow2523.c b/ext/ed25519-amd64-asm/fe25519_pow2523.c deleted file mode 100644 index 60042a0a..00000000 --- a/ext/ed25519-amd64-asm/fe25519_pow2523.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "fe25519.h" - -void fe25519_pow2523(fe25519 *r, const fe25519 *x) -{ - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t,&z2); - /* 8 */ fe25519_square(&t,&t); - /* 9 */ fe25519_mul(&z9,&t,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); - /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); - /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); - /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } - /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t,&t); - /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); - /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); - /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } - /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t,&t); - /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t,&t); - /* 2^252 - 2^2 */ fe25519_square(&t,&t); - /* 2^252 - 3 */ fe25519_mul(r,&t,x); -} diff --git a/ext/ed25519-amd64-asm/fe25519_setint.c b/ext/ed25519-amd64-asm/fe25519_setint.c deleted file mode 100644 index 585c4bdd..00000000 --- a/ext/ed25519-amd64-asm/fe25519_setint.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "fe25519.h" - -void fe25519_setint(fe25519 *r, unsigned int v) -{ - r->v[0] = v; - r->v[1] = 0; - r->v[2] = 0; - r->v[3] = 0; -} diff --git a/ext/ed25519-amd64-asm/fe25519_square.s b/ext/ed25519-amd64-asm/fe25519_square.s deleted file mode 100644 index a74d9e88..00000000 --- a/ext/ed25519-amd64-asm/fe25519_square.s +++ /dev/null @@ -1,639 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 squarer4 - -# qhasm: int64 squarer5 - -# qhasm: int64 squarer6 - -# qhasm: int64 squarer7 - -# qhasm: int64 squarer8 - -# qhasm: int64 squarerax - -# qhasm: int64 squarerdx - -# qhasm: int64 squaret1 - -# qhasm: int64 squaret2 - -# qhasm: int64 squaret3 - -# qhasm: int64 squarec - -# qhasm: int64 squarezero - -# qhasm: int64 squarei38 - -# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_square -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_fe25519_square -.globl crypto_sign_ed25519_amd64_64_fe25519_square -_crypto_sign_ed25519_amd64_64_fe25519_square: -crypto_sign_ed25519_amd64_64_fe25519_square: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarerax = *(uint64 *)(xp + 8) -# asm 1: movq 8(squarerax=int64#7 -# asm 2: movq 8(squarerax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) -# asm 1: mulq 0(r1=int64#5 -# asm 2: mov r1=%r8 -mov %rax,%r8 - -# qhasm: r2 = squarerdx -# asm 1: mov r2=int64#6 -# asm 2: mov r2=%r9 -mov %rdx,%r9 - -# qhasm: squarerax = *(uint64 *)(xp + 16) -# asm 1: movq 16(squarerax=int64#7 -# asm 2: movq 16(squarerax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 8) -# asm 1: mulq 8(r3=int64#8 -# asm 2: mov r3=%r10 -mov %rax,%r10 - -# qhasm: squarer4 = squarerdx -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rdx,%r11 - -# qhasm: squarerax = *(uint64 *)(xp + 24) -# asm 1: movq 24(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 16) -# asm 1: mulq 16(squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rax,%r12 - -# qhasm: squarer6 = squarerdx -# asm 1: mov squarer6=int64#11 -# asm 2: mov squarer6=%r13 -mov %rdx,%r13 - -# qhasm: squarerax = *(uint64 *)(xp + 16) -# asm 1: movq 16(squarerax=int64#7 -# asm 2: movq 16(squarerax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) -# asm 1: mulq 0(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 8) -# asm 1: mulq 8(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) -# asm 1: mulq 0(squarerax=int64#7 -# asm 2: movq 0(squarerax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 0) -# asm 1: mulq 0(r0=int64#12 -# asm 2: mov r0=%r14 -mov %rax,%r14 - -# qhasm: squaret1 = squarerdx -# asm 1: mov squaret1=int64#13 -# asm 2: mov squaret1=%r15 -mov %rdx,%r15 - -# qhasm: squarerax = *(uint64 *)(xp + 8) -# asm 1: movq 8(squarerax=int64#7 -# asm 2: movq 8(squarerax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 8) -# asm 1: mulq 8(squaret2=int64#14 -# asm 2: mov squaret2=%rbx -mov %rax,%rbx - -# qhasm: squaret3 = squarerdx -# asm 1: mov squaret3=int64#15 -# asm 2: mov squaret3=%rbp -mov %rdx,%rbp - -# qhasm: squarerax = *(uint64 *)(xp + 16) -# asm 1: movq 16(squarerax=int64#7 -# asm 2: movq 16(squarerax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 16) -# asm 1: mulq 16(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(xp + 24) -# asm 1: mulq 24(squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r11,%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: squarer4 = squarerax -# asm 1: mov squarer4=int64#2 -# asm 2: mov squarer4=%rsi -mov %rax,%rsi - -# qhasm: squarerax = squarer5 -# asm 1: mov squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r12,%rax - -# qhasm: squarer5 = squarerdx -# asm 1: mov squarer5=int64#9 -# asm 2: mov squarer5=%r11 -mov %rdx,%r11 - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? squarer5 += squarerax -# asm 1: add squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r13,%rax - -# qhasm: squarer6 = 0 -# asm 1: mov $0,>squarer6=int64#10 -# asm 2: mov $0,>squarer6=%r12 -mov $0,%r12 - -# qhasm: squarer6 += squarerdx + carry -# asm 1: adc squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %rcx,%rax - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarer7 += squarerdx + carry -# asm 1: adc squarer8=int64#7 -# asm 2: mov $0,>squarer8=%rax -mov $0,%rax - -# qhasm: squarer8 += squarerdx + carry -# asm 1: adc squarezero=int64#2 -# asm 2: mov $0,>squarezero=%rsi -mov $0,%rsi - -# qhasm: squarer8 += squarezero + carry -# asm 1: adc squarer8=int64#3 -# asm 2: imulq $38,squarer8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? r0 += squarer8 -# asm 1: add squarezero=int64#2 -# asm 2: imulq $38,squarezero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: r0 += squarezero -# asm 1: add caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/fe25519_sub.s b/ext/ed25519-amd64-asm/fe25519_sub.s deleted file mode 100644 index 0b395bce..00000000 --- a/ext/ed25519-amd64-asm/fe25519_sub.s +++ /dev/null @@ -1,189 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 subt0 - -# qhasm: int64 subt1 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_fe25519_sub -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_fe25519_sub -.globl crypto_sign_ed25519_amd64_64_fe25519_sub -_crypto_sign_ed25519_amd64_64_fe25519_sub: -crypto_sign_ed25519_amd64_64_fe25519_sub: -mov %rsp,%r11 -and $31,%r11 -add $0,%r11 -sub %r11,%rsp - -# qhasm: r0 = *(uint64 *)(xp + 0) -# asm 1: movq 0(r0=int64#4 -# asm 2: movq 0(r0=%rcx -movq 0(%rsi),%rcx - -# qhasm: r1 = *(uint64 *)(xp + 8) -# asm 1: movq 8(r1=int64#5 -# asm 2: movq 8(r1=%r8 -movq 8(%rsi),%r8 - -# qhasm: r2 = *(uint64 *)(xp + 16) -# asm 1: movq 16(r2=int64#6 -# asm 2: movq 16(r2=%r9 -movq 16(%rsi),%r9 - -# qhasm: r3 = *(uint64 *)(xp + 24) -# asm 1: movq 24(r3=int64#2 -# asm 2: movq 24(r3=%rsi -movq 24(%rsi),%rsi - -# qhasm: carry? r0 -= *(uint64 *)(yp + 0) -# asm 1: subq 0(subt0=int64#3 -# asm 2: mov $0,>subt0=%rdx -mov $0,%rdx - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#7 -# asm 2: mov $38,>subt1=%rax -mov $38,%rax - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae v[0] = *(unsigned long long *)x; - r->v[1] = *(((unsigned long long *)x)+1); - r->v[2] = *(((unsigned long long *)x)+2); - r->v[3] = *(((unsigned long long *)x)+3); - r->v[3] &= 0x7fffffffffffffffULL; -} diff --git a/ext/ed25519-amd64-asm/ge25519.h b/ext/ed25519-amd64-asm/ge25519.h deleted file mode 100644 index 0b15136b..00000000 --- a/ext/ed25519-amd64-asm/ge25519.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef GE25519_H -#define GE25519_H - -#include "fe25519.h" -#include "sc25519.h" - -#define ge25519 crypto_sign_ed25519_amd64_64_ge25519 -#define ge25519_base crypto_sign_ed25519_amd64_64_ge25519_base -#define ge25519_unpackneg_vartime crypto_sign_ed25519_amd64_64_unpackneg_vartime -#define ge25519_pack crypto_sign_ed25519_amd64_64_pack -#define ge25519_isneutral_vartime crypto_sign_ed25519_amd64_64_isneutral_vartime -#define ge25519_add crypto_sign_ed25519_amd64_64_ge25519_add -#define ge25519_double crypto_sign_ed25519_amd64_64_ge25519_double -#define ge25519_double_scalarmult_vartime crypto_sign_ed25519_amd64_64_double_scalarmult_vartime -#define ge25519_multi_scalarmult_vartime crypto_sign_ed25519_amd64_64_ge25519_multi_scalarmult_vartime -#define ge25519_scalarmult_base crypto_sign_ed25519_amd64_64_scalarmult_base -#define ge25519_p1p1_to_p2 crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 -#define ge25519_p1p1_to_p3 crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 -#define ge25519_add_p1p1 crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 -#define ge25519_dbl_p1p1 crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 -#define choose_t crypto_sign_ed25519_amd64_64_choose_t -#define ge25519_nielsadd2 crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 -#define ge25519_nielsadd_p1p1 crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 -#define ge25519_pnielsadd_p1p1 crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 - - -#define ge25519_p3 ge25519 - -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; - fe25519 t; -} ge25519; - -typedef struct -{ - fe25519 x; - fe25519 z; - fe25519 y; - fe25519 t; -} ge25519_p1p1; - -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; -} ge25519_p2; - -typedef struct -{ - fe25519 ysubx; - fe25519 xaddy; - fe25519 t2d; -} ge25519_niels; - -typedef struct -{ - fe25519 ysubx; - fe25519 xaddy; - fe25519 z; - fe25519 t2d; -} ge25519_pniels; - -extern void ge25519_p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p); -extern void ge25519_p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p); -extern void ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q); -extern void ge25519_dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p); -extern void choose_t(ge25519_niels *t, unsigned long long pos, signed long long b, const ge25519_niels *base_multiples); -extern void ge25519_nielsadd2(ge25519_p3 *r, const ge25519_niels *q); -extern void ge25519_nielsadd_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_niels *q); -extern void ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_pniels *q); - -extern const ge25519 ge25519_base; - -extern int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]); - -extern void ge25519_pack(unsigned char r[32], const ge25519 *p); - -extern int ge25519_isneutral_vartime(const ge25519 *p); - -extern void ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q); - -extern void ge25519_double(ge25519 *r, const ge25519 *p); - -/* computes [s1]p1 + [s2]ge25519_base */ -extern void ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const sc25519 *s1, const sc25519 *s2); - -extern void ge25519_multi_scalarmult_vartime(ge25519 *r, ge25519 *p, sc25519 *s, const unsigned long long npoints); - -extern void ge25519_scalarmult_base(ge25519 *r, const sc25519 *s); - -#endif diff --git a/ext/ed25519-amd64-asm/ge25519_add.c b/ext/ed25519-amd64-asm/ge25519_add.c deleted file mode 100644 index c4d1c68a..00000000 --- a/ext/ed25519-amd64-asm/ge25519_add.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "ge25519.h" - -void ge25519_add(ge25519_p3 *r, const ge25519_p3 *p, const ge25519_p3 *q) -{ - ge25519_p1p1 grp1p1; - ge25519_add_p1p1(&grp1p1, p, q); - ge25519_p1p1_to_p3(r, &grp1p1); -} diff --git a/ext/ed25519-amd64-asm/ge25519_add_p1p1.s b/ext/ed25519-amd64-asm/ge25519_add_p1p1.s deleted file mode 100644 index 0cb13898..00000000 --- a/ext/ed25519-amd64-asm/ge25519_add_p1p1.s +++ /dev/null @@ -1,4554 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 pp - -# qhasm: int64 qp - -# qhasm: input rp - -# qhasm: input pp - -# qhasm: input qp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 a0 - -# qhasm: int64 a1 - -# qhasm: int64 a2 - -# qhasm: int64 a3 - -# qhasm: stack64 a0_stack - -# qhasm: stack64 a1_stack - -# qhasm: stack64 a2_stack - -# qhasm: stack64 a3_stack - -# qhasm: int64 b0 - -# qhasm: int64 b1 - -# qhasm: int64 b2 - -# qhasm: int64 b3 - -# qhasm: stack64 b0_stack - -# qhasm: stack64 b1_stack - -# qhasm: stack64 b2_stack - -# qhasm: stack64 b3_stack - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: stack64 c0_stack - -# qhasm: stack64 c1_stack - -# qhasm: stack64 c2_stack - -# qhasm: stack64 c3_stack - -# qhasm: int64 d0 - -# qhasm: int64 d1 - -# qhasm: int64 d2 - -# qhasm: int64 d3 - -# qhasm: stack64 d0_stack - -# qhasm: stack64 d1_stack - -# qhasm: stack64 d2_stack - -# qhasm: stack64 d3_stack - -# qhasm: int64 t10 - -# qhasm: int64 t11 - -# qhasm: int64 t12 - -# qhasm: int64 t13 - -# qhasm: stack64 t10_stack - -# qhasm: stack64 t11_stack - -# qhasm: stack64 t12_stack - -# qhasm: stack64 t13_stack - -# qhasm: int64 t20 - -# qhasm: int64 t21 - -# qhasm: int64 t22 - -# qhasm: int64 t23 - -# qhasm: stack64 t20_stack - -# qhasm: stack64 t21_stack - -# qhasm: stack64 t22_stack - -# qhasm: stack64 t23_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 rt0 - -# qhasm: int64 rt1 - -# qhasm: int64 rt2 - -# qhasm: int64 rt3 - -# qhasm: int64 x0 - -# qhasm: int64 x1 - -# qhasm: int64 x2 - -# qhasm: int64 x3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: int64 addt0 - -# qhasm: int64 addt1 - -# qhasm: int64 subt0 - -# qhasm: int64 subt1 - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 -.globl crypto_sign_ed25519_amd64_64_ge25519_add_p1p1 -_crypto_sign_ed25519_amd64_64_ge25519_add_p1p1: -crypto_sign_ed25519_amd64_64_ge25519_add_p1p1: -mov %rsp,%r11 -and $31,%r11 -add $192,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: qp = qp -# asm 1: mov qp=int64#4 -# asm 2: mov qp=%rcx -mov %rdx,%rcx - -# qhasm: a0 = *(uint64 *)(pp + 32) -# asm 1: movq 32(a0=int64#3 -# asm 2: movq 32(a0=%rdx -movq 32(%rsi),%rdx - -# qhasm: a1 = *(uint64 *)(pp + 40) -# asm 1: movq 40(a1=int64#5 -# asm 2: movq 40(a1=%r8 -movq 40(%rsi),%r8 - -# qhasm: a2 = *(uint64 *)(pp + 48) -# asm 1: movq 48(a2=int64#6 -# asm 2: movq 48(a2=%r9 -movq 48(%rsi),%r9 - -# qhasm: a3 = *(uint64 *)(pp + 56) -# asm 1: movq 56(a3=int64#7 -# asm 2: movq 56(a3=%rax -movq 56(%rsi),%rax - -# qhasm: b0 = a0 -# asm 1: mov b0=int64#8 -# asm 2: mov b0=%r10 -mov %rdx,%r10 - -# qhasm: b1 = a1 -# asm 1: mov b1=int64#9 -# asm 2: mov b1=%r11 -mov %r8,%r11 - -# qhasm: b2 = a2 -# asm 1: mov b2=int64#10 -# asm 2: mov b2=%r12 -mov %r9,%r12 - -# qhasm: b3 = a3 -# asm 1: mov b3=int64#11 -# asm 2: mov b3=%r13 -mov %rax,%r13 - -# qhasm: carry? a0 -= *(uint64 *)(pp + 0) -# asm 1: subq 0(subt0=int64#12 -# asm 2: mov $0,>subt0=%r14 -mov $0,%r14 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#13 -# asm 2: mov $38,>subt1=%r15 -mov $38,%r15 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#12 -# asm 2: mov $0,>addt0=%r14 -mov $0,%r14 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#13 -# asm 2: mov $38,>addt1=%r15 -mov $38,%r15 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %rdx,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r8,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r9,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %rax,80(%rsp) - -# qhasm: b0_stack = b0 -# asm 1: movq b0_stack=stack64#12 -# asm 2: movq b0_stack=88(%rsp) -movq %r10,88(%rsp) - -# qhasm: b1_stack = b1 -# asm 1: movq b1_stack=stack64#13 -# asm 2: movq b1_stack=96(%rsp) -movq %r11,96(%rsp) - -# qhasm: b2_stack = b2 -# asm 1: movq b2_stack=stack64#14 -# asm 2: movq b2_stack=104(%rsp) -movq %r12,104(%rsp) - -# qhasm: b3_stack = b3 -# asm 1: movq b3_stack=stack64#15 -# asm 2: movq b3_stack=112(%rsp) -movq %r13,112(%rsp) - -# qhasm: t10 = *(uint64 *)(qp + 32) -# asm 1: movq 32(t10=int64#3 -# asm 2: movq 32(t10=%rdx -movq 32(%rcx),%rdx - -# qhasm: t11 = *(uint64 *)(qp + 40) -# asm 1: movq 40(t11=int64#5 -# asm 2: movq 40(t11=%r8 -movq 40(%rcx),%r8 - -# qhasm: t12 = *(uint64 *)(qp + 48) -# asm 1: movq 48(t12=int64#6 -# asm 2: movq 48(t12=%r9 -movq 48(%rcx),%r9 - -# qhasm: t13 = *(uint64 *)(qp + 56) -# asm 1: movq 56(t13=int64#7 -# asm 2: movq 56(t13=%rax -movq 56(%rcx),%rax - -# qhasm: t20 = t10 -# asm 1: mov t20=int64#8 -# asm 2: mov t20=%r10 -mov %rdx,%r10 - -# qhasm: t21 = t11 -# asm 1: mov t21=int64#9 -# asm 2: mov t21=%r11 -mov %r8,%r11 - -# qhasm: t22 = t12 -# asm 1: mov t22=int64#10 -# asm 2: mov t22=%r12 -mov %r9,%r12 - -# qhasm: t23 = t13 -# asm 1: mov t23=int64#11 -# asm 2: mov t23=%r13 -mov %rax,%r13 - -# qhasm: carry? t10 -= *(uint64 *) (qp + 0) -# asm 1: subq 0(subt0=int64#12 -# asm 2: mov $0,>subt0=%r14 -mov $0,%r14 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#13 -# asm 2: mov $38,>subt1=%r15 -mov $38,%r15 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#12 -# asm 2: mov $0,>addt0=%r14 -mov $0,%r14 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#13 -# asm 2: mov $38,>addt1=%r15 -mov $38,%r15 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae t10_stack=stack64#16 -# asm 2: movq t10_stack=120(%rsp) -movq %rdx,120(%rsp) - -# qhasm: t11_stack = t11 -# asm 1: movq t11_stack=stack64#17 -# asm 2: movq t11_stack=128(%rsp) -movq %r8,128(%rsp) - -# qhasm: t12_stack = t12 -# asm 1: movq t12_stack=stack64#18 -# asm 2: movq t12_stack=136(%rsp) -movq %r9,136(%rsp) - -# qhasm: t13_stack = t13 -# asm 1: movq t13_stack=stack64#19 -# asm 2: movq t13_stack=144(%rsp) -movq %rax,144(%rsp) - -# qhasm: t20_stack = t20 -# asm 1: movq t20_stack=stack64#20 -# asm 2: movq t20_stack=152(%rsp) -movq %r10,152(%rsp) - -# qhasm: t21_stack = t21 -# asm 1: movq t21_stack=stack64#21 -# asm 2: movq t21_stack=160(%rsp) -movq %r11,160(%rsp) - -# qhasm: t22_stack = t22 -# asm 1: movq t22_stack=stack64#22 -# asm 2: movq t22_stack=168(%rsp) -movq %r12,168(%rsp) - -# qhasm: t23_stack = t23 -# asm 1: movq t23_stack=stack64#23 -# asm 2: movq t23_stack=176(%rsp) -movq %r13,176(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = a0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 56(%rsp),%r12 - -# qhasm: mulrax = t10_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a0=int64#11 -# asm 2: mov a0=%r13 -mov %rax,%r13 - -# qhasm: a1 = mulrdx -# asm 1: mov a1=int64#12 -# asm 2: mov a1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = t11_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a2=int64#13 -# asm 2: mov $0,>a2=%r15 -mov $0,%r15 - -# qhasm: a2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a3=int64#14 -# asm 2: mov $0,>a3=%rbx -mov $0,%rbx - -# qhasm: a3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 64(%rsp),%r12 - -# qhasm: mulrax = t10_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 72(%rsp),%r12 - -# qhasm: mulrax = t10_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 80(%rsp),%r12 - -# qhasm: mulrax = t10_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? a0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: a0 += mulzero -# asm 1: add a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %r13,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r14,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r15,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %rbx,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = b0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 88(%rsp),%r12 - -# qhasm: mulrax = t20_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx0=int64#11 -# asm 2: mov rx0=%r13 -mov %rax,%r13 - -# qhasm: rx1 = mulrdx -# asm 1: mov rx1=int64#12 -# asm 2: mov rx1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = t21_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx2=int64#13 -# asm 2: mov $0,>rx2=%r15 -mov $0,%r15 - -# qhasm: rx2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx3=int64#14 -# asm 2: mov $0,>rx3=%rbx -mov $0,%rbx - -# qhasm: rx3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 96(%rsp),%r12 - -# qhasm: mulrax = t20_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 104(%rsp),%r12 - -# qhasm: mulrax = t20_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 112(%rsp),%r12 - -# qhasm: mulrax = t20_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? rx0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: rx0 += mulzero -# asm 1: add ry0=int64#3 -# asm 2: mov ry0=%rdx -mov %r13,%rdx - -# qhasm: ry1 = rx1 -# asm 1: mov ry1=int64#5 -# asm 2: mov ry1=%r8 -mov %r14,%r8 - -# qhasm: ry2 = rx2 -# asm 1: mov ry2=int64#6 -# asm 2: mov ry2=%r9 -mov %r15,%r9 - -# qhasm: ry3 = rx3 -# asm 1: mov ry3=int64#7 -# asm 2: mov ry3=%rax -mov %rbx,%rax - -# qhasm: carry? ry0 += a0_stack -# asm 1: addq addt0=int64#8 -# asm 2: mov $0,>addt0=%r10 -mov $0,%r10 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#9 -# asm 2: mov $38,>addt1=%r11 -mov $38,%r11 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae subt0=int64#8 -# asm 2: mov $0,>subt0=%r10 -mov $0,%r10 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#9 -# asm 2: mov $38,>subt1=%r11 -mov $38,%r11 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulx0=int64#10 -# asm 2: movq 96(mulx0=%r12 -movq 96(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c0=int64#11 -# asm 2: mov c0=%r13 -mov %rax,%r13 - -# qhasm: c1 = mulrdx -# asm 1: mov c1=int64#12 -# asm 2: mov c1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 104) -# asm 1: movq 104(mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c2=int64#13 -# asm 2: mov $0,>c2=%r15 -mov $0,%r15 - -# qhasm: c2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c3=int64#14 -# asm 2: mov $0,>c3=%rbx -mov $0,%rbx - -# qhasm: c3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq 104(mulx1=%r12 -movq 104(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq 112(mulx2=%r12 -movq 112(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq 120(mulx3=%r12 -movq 120(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? c0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: c0 += mulzero -# asm 1: add c0_stack=stack64#8 -# asm 2: movq c0_stack=56(%rsp) -movq %r13,56(%rsp) - -# qhasm: c1_stack = c1 -# asm 1: movq c1_stack=stack64#9 -# asm 2: movq c1_stack=64(%rsp) -movq %r14,64(%rsp) - -# qhasm: c2_stack = c2 -# asm 1: movq c2_stack=stack64#10 -# asm 2: movq c2_stack=72(%rsp) -movq %r15,72(%rsp) - -# qhasm: c3_stack = c3 -# asm 1: movq c3_stack=stack64#11 -# asm 2: movq c3_stack=80(%rsp) -movq %rbx,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = c0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 56(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 -# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c0=int64#11 -# asm 2: mov c0=%r13 -mov %rax,%r13 - -# qhasm: c1 = mulrdx -# asm 1: mov c1=int64#12 -# asm 2: mov c1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D1 -# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c2=int64#13 -# asm 2: mov $0,>c2=%r15 -mov $0,%r15 - -# qhasm: c2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c3=int64#14 -# asm 2: mov $0,>c3=%rbx -mov $0,%rbx - -# qhasm: c3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 64(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 -# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 72(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 -# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 80(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)&crypto_sign_ed25519_amd64_64_EC2D0 -# asm 1: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D0,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D0(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D1,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D1(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D2,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D2(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq crypto_sign_ed25519_amd64_64_EC2D3,>mulrax=%rax -movq crypto_sign_ed25519_amd64_64_EC2D3(%rip),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? c0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: c0 += mulzero -# asm 1: add c0_stack=stack64#8 -# asm 2: movq c0_stack=56(%rsp) -movq %r13,56(%rsp) - -# qhasm: c1_stack = c1 -# asm 1: movq c1_stack=stack64#9 -# asm 2: movq c1_stack=64(%rsp) -movq %r14,64(%rsp) - -# qhasm: c2_stack = c2 -# asm 1: movq c2_stack=stack64#10 -# asm 2: movq c2_stack=72(%rsp) -movq %r15,72(%rsp) - -# qhasm: c3_stack = c3 -# asm 1: movq c3_stack=stack64#11 -# asm 2: movq c3_stack=80(%rsp) -movq %rbx,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulx0=int64#10 -# asm 2: movq 64(mulx0=%r12 -movq 64(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt0=int64#11 -# asm 2: mov rt0=%r13 -mov %rax,%r13 - -# qhasm: rt1 = mulrdx -# asm 1: mov rt1=int64#12 -# asm 2: mov rt1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 72) -# asm 1: movq 72(mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt2=int64#13 -# asm 2: mov $0,>rt2=%r15 -mov $0,%r15 - -# qhasm: rt2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt3=int64#14 -# asm 2: mov $0,>rt3=%rbx -mov $0,%rbx - -# qhasm: rt3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq 72(mulx1=%r12 -movq 72(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq 80(mulx2=%r12 -movq 80(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#2 -# asm 2: movq 88(mulx3=%rsi -movq 88(%rsi),%rsi - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rt0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rt0 += mulzero -# asm 1: add addt0=int64#2 -# asm 2: mov $0,>addt0=%rsi -mov $0,%rsi - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#3 -# asm 2: mov $38,>addt1=%rdx -mov $38,%rdx - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae rz0=int64#2 -# asm 2: mov rz0=%rsi -mov %r13,%rsi - -# qhasm: rz1 = rt1 -# asm 1: mov rz1=int64#3 -# asm 2: mov rz1=%rdx -mov %r14,%rdx - -# qhasm: rz2 = rt2 -# asm 1: mov rz2=int64#4 -# asm 2: mov rz2=%rcx -mov %r15,%rcx - -# qhasm: rz3 = rt3 -# asm 1: mov rz3=int64#5 -# asm 2: mov rz3=%r8 -mov %rbx,%r8 - -# qhasm: carry? rz0 += c0_stack -# asm 1: addq addt0=int64#6 -# asm 2: mov $0,>addt0=%r9 -mov $0,%r9 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#7 -# asm 2: mov $38,>addt1=%rax -mov $38,%rax - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae subt0=int64#6 -# asm 2: mov $0,>subt0=%r9 -mov $0,%r9 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#7 -# asm 2: mov $38,>subt1=%rax -mov $38,%rax - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_base.c b/ext/ed25519-amd64-asm/ge25519_base.c deleted file mode 100644 index a7ae9786..00000000 --- a/ext/ed25519-amd64-asm/ge25519_base.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "ge25519.h" - -const ge25519 ge25519_base = {{{0xC9562D608F25D51A, 0x692CC7609525A7B2, 0xC0A4E231FDD6DC5C, 0x216936D3CD6E53FE}}, - {{0x6666666666666658, 0x6666666666666666, 0x6666666666666666, 0x6666666666666666}}, - {{0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 000000000000000000}}, - {{0x6DDE8AB3A5B7DDA3, 0x20F09F80775152F5, 0x66EA4E8E64ABE37D, 0x67875F0FD78B7665}}}; - diff --git a/ext/ed25519-amd64-asm/ge25519_base_niels.data b/ext/ed25519-amd64-asm/ge25519_base_niels.data deleted file mode 100644 index 8e3300cf..00000000 --- a/ext/ed25519-amd64-asm/ge25519_base_niels.data +++ /dev/null @@ -1,1536 +0,0 @@ -{{{0x9d103905d740913e, 0xfd399f05d140beb3, 0xa5c18434688f8a09, 0x44fd2f9298f81267}}, - {{0x2fbc93c6f58c3b85, 0xcf932dc6fb8c0e19, 0x270b4898643d42c2, 0x07cf9d3a33d4ba65}}, - {{0xdbbd15674b6fbb59, 0x41e13f00eea2a5ea, 0xcdd49d1cc957c6fa, 0x4f0ebe1faf16ecca}}}, -{{{0x8a99a56042b4d5a8, 0x8f2b810c4e60acf6, 0xe09e236bb16e37aa, 0x6bb595a669c92555}}, - {{0x9224e7fc933c71d7, 0x9f469d967a0ff5b5, 0x5aa69a65e1d60702, 0x590c063fa87d2e2e}}, - {{0x6e347eaadad36802, 0xbaf3599383ee4805, 0x3bcabe10e6076826, 0x49314f0a165ed1b8}}}, -{{{0x56611fe8a4fcd265, 0x3bd353fde5c1ba7d, 0x8131f31a214bd6bd, 0x2ab91587555bda62}}, - {{0xaf25b0a84cee9730, 0x025a8430e8864b8a, 0xc11b50029f016732, 0x7a164e1b9a80f8f4}}, - {{0x9bf211f4f1674834, 0xb84e6b17f62df895, 0xd7de6f075b722a4e, 0x549a04b963bb2a21}}}, -{{{0x95fe050a056818bf, 0x327e89715660faa9, 0xc3e8e3cd06a05073, 0x27933f4c7445a49a}}, - {{0x287351b98efc099f, 0x6765c6f47dfd2538, 0xca348d3dfb0a9265, 0x680e910321e58727}}, - {{0xbf1e45ece51426b0, 0xe32bc63d6dba0f94, 0xe42974d58cf852c0, 0x44f079b1b0e64c18}}}, -{{{0x7f9182c3a447d6ba, 0xd50014d14b2729b7, 0xe33cf11cb864a087, 0x154a7e73eb1b55f3}}, - {{0xa212bc4408a5bb33, 0x8d5048c3c75eed02, 0xdd1beb0c5abfec44, 0x2945ccf146e206eb}}, - {{0xc832a179e7d003b3, 0x5f729d0a00124d7e, 0x62c1d4a10e6d8ff3, 0x68b8ac5938b27a98}}}, -{{{0x499806b67b7d8ca4, 0x575be28427d22739, 0xbb085ce7204553b9, 0x38b64c41ae417884}}, - {{0x3a0ceeeb77157131, 0x9b27158900c8af88, 0x8065b668da59a736, 0x51e57bb6a2cc38bd}}, - {{0x8f9dad91689de3a4, 0x175f2428f8fb9137, 0x050ab5329fcfb988, 0x7865dfa21354c09f}}}, -{{{0xba6f2c9aaa3221b1, 0x6ca021533bba23a7, 0x9dea764f92192c3a, 0x1d6edd5d2e5317e0}}, - {{0x6b1a5cd0944ea3bf, 0x7470353ab39dc0d2, 0x71b2528228542e49, 0x461bea69283c927e}}, - {{0x217a8aacab0fda36, 0xa528c6543d3549c8, 0x37d05b8b13ab7568, 0x233cef623a2cbc37}}}, -{{{0xe2a75dedf39234d9, 0x963d7680e1b558f9, 0x2c2741ac6e3c23fb, 0x3a9024a1320e01c3}}, - {{0x59b7596604dd3e8f, 0x6cb30377e288702c, 0xb1339c665ed9c323, 0x0915e76061bce52f}}, - {{0xdf7de835a834a37e, 0x8be19cda689857ea, 0x2c1185367167b326, 0x589eb3d9dbefd5c2}}}, -{{{0x7ec851ca553e2df3, 0xa71284cba64878b3, 0xe6b5e4193288d1e7, 0x4cf210ec5a9a8883}}, - {{0x322d04a52d9021f6, 0xb9c19f3375c6bf9c, 0x587a3a4342d20b09, 0x143b1cf8aa64fe61}}, - {{0x9f867c7d968acaab, 0x5f54258e27092729, 0xd0a7d34bea180975, 0x21b546a3374126e1}}}, -{{{0xa94ff858a2888343, 0xce0ed4565313ed3c, 0xf55c3dcfb5bf34fa, 0x0a653ca5c9eab371}}, - {{0x490a7a45d185218f, 0x9a15377846049335, 0x0060ea09cc31e1f6, 0x7e041577f86ee965}}, - {{0x66b2a496ce5b67f3, 0xff5492d8bd569796, 0x503cec294a592cd0, 0x566943650813acb2}}}, -{{{0xb818db0c26620798, 0x5d5c31d9606e354a, 0x0982fa4f00a8cdc7, 0x17e12bcd4653e2d4}}, - {{0x5672f9eb1dabb69d, 0xba70b535afe853fc, 0x47ac0f752796d66d, 0x32a5351794117275}}, - {{0xd3a644a6df648437, 0x703b6559880fbfdd, 0xcb852540ad3a1aa5, 0x0900b3f78e4c6468}}}, -{{{0x0a851b9f679d651b, 0xe108cb61033342f2, 0xd601f57fe88b30a3, 0x371f3acaed2dd714}}, - {{0xed280fbec816ad31, 0x52d9595bd8e6efe3, 0x0fe71772f6c623f5, 0x4314030b051e293c}}, - {{0xd560005efbf0bcad, 0x8eb70f2ed1870c5e, 0x201f9033d084e6a0, 0x4c3a5ae1ce7b6670}}}, -{{{0x4138a434dcb8fa95, 0x870cf67d6c96840b, 0xde388574297be82c, 0x7c814db27262a55a}}, - {{0xbaf875e4c93da0dd, 0xb93282a771b9294d, 0x80d63fb7f4c6c460, 0x6de9c73dea66c181}}, - {{0x478904d5a04df8f2, 0xfafbae4ab10142d3, 0xf6c8ac63555d0998, 0x5aac4a412f90b104}}}, -{{{0xc64f326b3ac92908, 0x5551b282e663e1e0, 0x476b35f54a1a4b83, 0x1b9da3fe189f68c2}}, - {{0x603a0d0abd7f5134, 0x8089c932e1d3ae46, 0xdf2591398798bd63, 0x1c145cd274ba0235}}, - {{0x32e8386475f3d743, 0x365b8baf6ae5d9ef, 0x825238b6385b681e, 0x234929c1167d65e1}}}, -{{{0x984decaba077ade8, 0x383f77ad19eb389d, 0xc7ec6b7e2954d794, 0x59c77b3aeb7c3a7a}}, - {{0x48145cc21d099fcf, 0x4535c192cc28d7e5, 0x80e7c1e548247e01, 0x4a5f28743b2973ee}}, - {{0xd3add725225ccf62, 0x911a3381b2152c5d, 0xd8b39fad5b08f87d, 0x6f05606b4799fe3b}}}, -{{{0x9ffe9e92177ba962, 0x98aee71d0de5cae1, 0x3ff4ae942d831044, 0x714de12e58533ac8}}, - {{0x5b433149f91b6483, 0xadb5dc655a2cbf62, 0x87fa8412632827b3, 0x60895e91ab49f8d8}}, - {{0xe9ecf2ed0cf86c18, 0xb46d06120735dfd4, 0xbc9da09804b96be7, 0x73e2e62fd96dc26b}}}, -{{{0xed5b635449aa515e, 0xa865c49f0bc6823a, 0x850c1fe95b42d1c4, 0x30d76d6f03d315b9}}, - {{0x2eccdd0e632f9c1d, 0x51d0b69676893115, 0x52dfb76ba8637a58, 0x6dd37d49a00eef39}}, - {{0x6c4444172106e4c7, 0xfb53d680928d7f69, 0xb4739ea4694d3f26, 0x10c697112e864bb0}}}, -{{{0x6493c4277dbe5fde, 0x265d4fad19ad7ea2, 0x0e00dfc846304590, 0x25e61cabed66fe09}}, - {{0x0ca62aa08358c805, 0x6a3d4ae37a204247, 0x7464d3a63b11eddc, 0x03bf9baf550806ef}}, - {{0x3f13e128cc586604, 0x6f5873ecb459747e, 0xa0b63dedcc1268f5, 0x566d78634586e22c}}}, -{{{0x1637a49f9cc10834, 0xbc8e56d5a89bc451, 0x1cb5ec0f7f7fd2db, 0x33975bca5ecc35d9}}, - {{0xa1054285c65a2fd0, 0x6c64112af31667c3, 0x680ae240731aee58, 0x14fba5f34793b22a}}, - {{0x3cd746166985f7d4, 0x593e5e84c9c80057, 0x2fc3f2b67b61131e, 0x14829cea83fc526c}}}, -{{{0xff437b8497dd95c2, 0x6c744e30aa4eb5a7, 0x9e0c5d613c85e88b, 0x2fd9c71e5f758173}}, - {{0x21e70b2f4e71ecb8, 0xe656ddb940a477e3, 0xbf6556cece1d4f80, 0x05fc3bc4535d7b7e}}, - {{0x24b8b3ae52afdedd, 0x3495638ced3b30cf, 0x33a4bc83a9be8195, 0x373767475c651f04}}}, -{{{0x2fba99fd40d1add9, 0xb307166f96f4d027, 0x4363f05215f03bae, 0x1fbea56c3b18f999}}, - {{0x634095cb14246590, 0xef12144016c15535, 0x9e38140c8910bc60, 0x6bf5905730907c8c}}, - {{0x0fa778f1e1415b8a, 0x06409ff7bac3a77e, 0x6f52d7b89aa29a50, 0x02521cf67a635a56}}}, -{{{0x513fee0b0a9d5294, 0x8f98e75c0fdf5a66, 0xd4618688bfe107ce, 0x3fa00a7e71382ced}}, - {{0xb1146720772f5ee4, 0xe8f894b196079ace, 0x4af8224d00ac824a, 0x001753d9f7cd6cc4}}, - {{0x3c69232d963ddb34, 0x1dde87dab4973858, 0xaad7d1f9a091f285, 0x12b5fe2fa048edb6}}}, -{{{0x71f0fbc496fce34d, 0x73b9826badf35bed, 0xd2047261ff28c561, 0x749b76f96fb1206f}}, - {{0xdf2b7c26ad6f1e92, 0x4b66d323504b8913, 0x8c409dc0751c8bc3, 0x6f7e93c20796c7b8}}, - {{0x1f5af604aea6ae05, 0xc12351f1bee49c99, 0x61a808b5eeff6b66, 0x0fcec10f01e02151}}}, -{{{0x644d58a649fe1e44, 0x21fcaea231ad777e, 0x02441c5a887fd0d2, 0x4901aa7183c511f3}}, - {{0x3df2d29dc4244e45, 0x2b020e7493d8de0a, 0x6cc8067e820c214d, 0x413779166feab90a}}, - {{0x08b1b7548c1af8f0, 0xce0f7a7c246299b4, 0xf760b0f91e06d939, 0x41bb887b726d1213}}}, -{{{0x9267806c567c49d8, 0x066d04ccca791e6a, 0xa69f5645e3cc394b, 0x5c95b686a0788cd2}}, - {{0x97d980e0aa39f7d2, 0x35d0384252c6b51c, 0x7d43f49307cd55aa, 0x56bd36cfb78ac362}}, - {{0x2ac519c10d14a954, 0xeaf474b494b5fa90, 0xe6af8382a9f87a5a, 0x0dea6db1879be094}}}, -{{{0xaa66bf547344e5ab, 0xda1258888f1b4309, 0x5e87d2b3fd564b2f, 0x5b2c78885483b1dd}}, - {{0x15baeb74d6a8797a, 0x7ef55cf1fac41732, 0x29001f5a3c8b05c5, 0x0ad7cc8752eaccfb}}, - {{0x52151362793408cf, 0xeb0f170319963d94, 0xa833b2fa883d9466, 0x093a7fa775003c78}}}, -{{{0xe5107de63a16d7be, 0xa377ffdc9af332cf, 0x70d5bf18440b677f, 0x6a252b19a4a31403}}, - {{0xb8e9604460a91286, 0x7f3fd8047778d3de, 0x67d01e31bf8a5e2d, 0x7b038a06c27b653e}}, - {{0x9ed919d5d36990f3, 0x5213aebbdb4eb9f2, 0xc708ea054cb99135, 0x58ded57f72260e56}}}, -{{{0x78e79dade9413d77, 0xf257f9d59729e67d, 0x59db910ee37aa7e6, 0x6aa11b5bbb9e039c}}, - {{0xda6d53265b0fd48b, 0x8960823193bfa988, 0xd78ac93261d57e28, 0x79f2942d3a5c8143}}, - {{0x97da2f25b6c88de9, 0x251ba7eaacf20169, 0x09b44f87ef4eb4e4, 0x7d90ab1bbc6a7da5}}}, -{{{0x9acca683a7016bfe, 0x90505f4df2c50b6d, 0x6b610d5fcce435aa, 0x19a10d446198ff96}}, - {{0x1a07a3f496b3c397, 0x11ceaa188f4e2532, 0x7d9498d5a7751bf0, 0x19ed161f508dd8a0}}, - {{0x560a2cd687dce6ca, 0x7f3568c48664cf4d, 0x8741e95222803a38, 0x483bdab1595653fc}}}, -{{{0xfa780f148734fa49, 0x106f0b70360534e0, 0x2210776fe3e307bd, 0x3286c109dde6a0fe}}, - {{0xd6cf4d0ab4da80f6, 0x82483e45f8307fe0, 0x05005269ae6f9da4, 0x1c7052909cf7877a}}, - {{0x32ee7de2874e98d4, 0x14c362e9b97e0c60, 0x5781dcde6a60a38a, 0x217dd5eaaa7aa840}}}, -{{{0x9db7c4d0248e1eb0, 0xe07697e14d74bf52, 0x1e6a9b173c562354, 0x7fa7c21f795a4965}}, - {{0x8bdf1fb9be8c0ec8, 0x00bae7f8e30a0282, 0x4963991dad6c4f6c, 0x07058a6e5df6f60a}}, - {{0xe9eb02c4db31f67f, 0xed25fd8910bcfb2b, 0x46c8131f5c5cddb4, 0x33b21c13a0cb9bce}}}, -{{{0x360692f8087d8e31, 0xf4dcc637d27163f7, 0x25a4e62065ea5963, 0x659bf72e5ac160d9}}, - {{0x9aafb9b05ee38c5b, 0xbf9d2d4e071a13c7, 0x8eee6e6de933290a, 0x1c3bab17ae109717}}, - {{0x1c9ab216c7cab7b0, 0x7d65d37407bbc3cc, 0x52744750504a58d5, 0x09f2606b131a2990}}}, -{{{0x40e87d44744346be, 0x1d48dad415b52b25, 0x7c3a8a18a13b603e, 0x4eb728c12fcdbdf7}}, - {{0x7e234c597c6691ae, 0x64889d3d0a85b4c8, 0xdae2c90c354afae7, 0x0a871e070c6a9e1d}}, - {{0x3301b5994bbc8989, 0x736bae3a5bdd4260, 0x0d61ade219d59e3c, 0x3ee7300f2685d464}}}, -{{{0xf5d255e49e7dd6b7, 0x8016115c610b1eac, 0x3c99975d92e187ca, 0x13815762979125c2}}, - {{0x43fa7947841e7518, 0xe5c6fa59639c46d7, 0xa1065e1de3052b74, 0x7d47c6a2cfb89030}}, - {{0x3fdad0148ef0d6e0, 0x9d3e749a91546f3c, 0x71ec621026bb8157, 0x148cf58d34c9ec80}}}, -{{{0x46a492f67934f027, 0x469984bef6840aa9, 0x5ca1bc2a89611854, 0x3ff2fa1ebd5dbbd4}}, - {{0xe2572f7d9ae4756d, 0x56c345bb88f3487f, 0x9fd10b6d6960a88d, 0x278febad4eaea1b9}}, - {{0xb1aa681f8c933966, 0x8c21949c20290c98, 0x39115291219d3c52, 0x4104dd02fe9c677b}}}, -{{{0x72b2bf5e1124422a, 0xa1fa0c3398a33ab5, 0x94cb6101fa52b666, 0x2c863b00afaf53d5}}, - {{0x81214e06db096ab8, 0x21a8b6c90ce44f35, 0x6524c12a409e2af5, 0x0165b5a48efca481}}, - {{0xf190a474a0846a76, 0x12eff984cd2f7cc0, 0x695e290658aa2b8f, 0x591b67d9bffec8b8}}}, -{{{0x312f0d1c80b49bfa, 0x5979515eabf3ec8a, 0x727033c09ef01c88, 0x3de02ec7ca8f7bcb}}, - {{0x99b9b3719f18b55d, 0xe465e5faa18c641e, 0x61081136c29f05ed, 0x489b4f867030128b}}, - {{0xd232102d3aeb92ef, 0xe16253b46116a861, 0x3d7eabe7190baa24, 0x49f5fbba496cbebf}}}, -{{{0x30949a108a5bcfd4, 0xdc40dd70bc6473eb, 0x92c294c1307c0d1c, 0x5604a86dcbfa6e74}}, - {{0x155d628c1e9c572e, 0x8a4d86acc5884741, 0x91a352f6515763eb, 0x06a1a6c28867515b}}, - {{0x7288d1d47c1764b6, 0x72541140e0418b51, 0x9f031a6018acf6d1, 0x20989e89fe2742c6}}}, -{{{0x499777fd3a2dcc7f, 0x32857c2ca54fd892, 0xa279d864d207e3a0, 0x0403ed1d0ca67e29}}, - {{0x1674278b85eaec2e, 0x5621dc077acb2bdf, 0x640a4c1661cbf45a, 0x730b9950f70595d3}}, - {{0xc94b2d35874ec552, 0xc5e6c8cf98246f8d, 0xf7cb46fa16c035ce, 0x5bd7454308303dcc}}}, -{{{0x7f9ad19528b24cc2, 0x7f6b54656335c181, 0x66b8b66e4fc07236, 0x133a78007380ad83}}, - {{0x85c4932115e7792a, 0xc64c89a2bdcdddc9, 0x9d1e3da8ada3d762, 0x5bb7db123067f82c}}, - {{0x0961f467c6ca62be, 0x04ec21d6211952ee, 0x182360779bd54770, 0x740dca6d58f0e0d2}}}, -{{{0x50b70bf5d3f0af0b, 0x4feaf48ae32e71f7, 0x60e84ed3a55bbd34, 0x00ed489b3f50d1ed}}, - {{0x3906c72aed261ae5, 0x9ab68fd988e100f7, 0xf5e9059af3360197, 0x0e53dc78bf2b6d47}}, - {{0xb90829bf7971877a, 0x5e4444636d17e631, 0x4d05c52e18276893, 0x27632d9a5a4a4af5}}}, -{{{0xd11ff05154b260ce, 0xd86dc38e72f95270, 0x601fcd0d267cc138, 0x2b67916429e90ccd}}, - {{0xa98285d187eaffdb, 0xa5b4fbbbd8d0a864, 0xb658f27f022663f7, 0x3bbc2b22d99ce282}}, - {{0xb917c952583c0a58, 0x653ff9b80fe4c6f3, 0x9b0da7d7bcdf3c0c, 0x43a0eeb6ab54d60e}}}, -{{{0x396966a46d4a5487, 0xf811a18aac2bb3ba, 0x66e4685b5628b26b, 0x70a477029d929b92}}, - {{0x3ac6322357875fe8, 0xd9d4f4ecf5fbcb8f, 0x8dee8493382bb620, 0x50c5eaa14c799fdc}}, - {{0xdd0edc8bd6f2fb3c, 0x54c63aa79cc7b7a0, 0xae0b032b2c8d9f1a, 0x6f9ce107602967fb}}}, -{{{0xad1054b1cde1c22a, 0xc4a8e90248eb32df, 0x5f3e7b33accdc0ea, 0x72364713fc79963e}}, - {{0x139693063520e0b5, 0x437fcf7c88ea03fe, 0xf7d4c40bd3c959bc, 0x699154d1f893ded9}}, - {{0x315d5c75b4b27526, 0xcccb842d0236daa5, 0x22f0c8a3345fee8e, 0x73975a617d39dbed}}}, -{{{0xe4024df96375da10, 0x78d3251a1830c870, 0x902b1948658cd91c, 0x7e18b10b29b7438a}}, - {{0x6f37f392f4433e46, 0x0e19b9a11f566b18, 0x220fb78a1fd1d662, 0x362a4258a381c94d}}, - {{0x9071d9132b6beb2f, 0x0f26e9ad28418247, 0xeab91ec9bdec925d, 0x4be65bc8f48af2de}}}, -{{{0x78487feba36e7028, 0x5f3f13001dd8ce34, 0x934fb12d4b30c489, 0x056c244d397f0a2b}}, - {{0x1d50fba257c26234, 0x7bd4823adeb0678b, 0xc2b0dc6ea6538af5, 0x5665eec6351da73e}}, - {{0xdb3ee00943bfb210, 0x4972018720800ac2, 0x26ab5d6173bd8667, 0x20b209c2ab204938}}}, -{{{0x549e342ac07fb34b, 0x02d8220821373d93, 0xbc262d70acd1f567, 0x7a92c9fdfbcac784}}, - {{0x1fcca94516bd3289, 0x448d65aa41420428, 0x59c3b7b216a55d62, 0x49992cc64e612cd8}}, - {{0x65bd1bea70f801de, 0x1befb7c0fe49e28a, 0xa86306cdb1b2ae4a, 0x3b7ac0cd265c2a09}}}, -{{{0x822bee438c01bcec, 0x530cb525c0fbc73b, 0x48519034c1953fe9, 0x265cc261e09a0f5b}}, - {{0xf0d54e4f22ed39a7, 0xa2aae91e5608150a, 0xf421b2e9eddae875, 0x31bc531d6b7de992}}, - {{0xdf3d134da980f971, 0x7a4fb8d1221a22a7, 0x3df7d42035aad6d8, 0x2a14edcc6a1a125e}}}, -{{{0xdf48ee0752cfce4e, 0xc3fffaf306ec08b7, 0x05710b2ab95459c4, 0x161d25fa963ea38d}}, - {{0x231a8c570478433c, 0xb7b5270ec281439d, 0xdbaa99eae3d9079f, 0x2c03f5256c2b03d9}}, - {{0x790f18757b53a47d, 0x307b0130cf0c5879, 0x31903d77257ef7f9, 0x699468bdbd96bbaf}}}, -{{{0xbd1f2f46f4dafecf, 0x7cef0114a47fd6f7, 0xd31ffdda4a47b37f, 0x525219a473905785}}, - {{0xd8dd3de66aa91948, 0x485064c22fc0d2cc, 0x9b48246634fdea2f, 0x293e1c4e6c4a2e3a}}, - {{0x376e134b925112e1, 0x703778b5dca15da0, 0xb04589af461c3111, 0x5b605c447f032823}}}, -{{{0xb965805920c47c89, 0xe7f0100c923b8fcc, 0x0001256502e2ef77, 0x24a76dcea8aeb3ee}}, - {{0x3be9fec6f0e7f04c, 0x866a579e75e34962, 0x5542ef161e1de61a, 0x2f12fef4cc5abdd5}}, - {{0x0a4522b2dfc0c740, 0x10d06e7f40c9a407, 0xc6cf144178cff668, 0x5e607b2518a43790}}}, -{{{0x58b31d8f6cdf1818, 0x35cfa74fc36258a2, 0xe1b3ff4f66e61d6e, 0x5067acab6ccdd5f7}}, - {{0xa02c431ca596cf14, 0xe3c42d40aed3e400, 0xd24526802e0f26db, 0x201f33139e457068}}, - {{0xfd527f6b08039d51, 0x18b14964017c0006, 0xd5220eb02e25a4a8, 0x397cba8862460375}}}, -{{{0x30c13093f05959b2, 0xe23aa18de9a97976, 0x222fd491721d5e26, 0x2339d320766e6c3a}}, - {{0x7815c3fbc81379e7, 0xa6619420dde12af1, 0xffa9c0f885a8fdd5, 0x771b4022c1e1c252}}, - {{0xd87dd986513a2fa7, 0xf5ac9b71f9d4cf08, 0xd06bc31b1ea283b3, 0x331a189219971a76}}}, -{{{0xf5166f45fb4f80c6, 0x9c36c7de61c775cf, 0xe3d4e81b9041d91c, 0x31167c6b83bdfe21}}, - {{0x26512f3a9d7572af, 0x5bcbe28868074a9e, 0x84edc1c11180f7c4, 0x1ac9619ff649a67b}}, - {{0xf22b3842524b1068, 0x5068343bee9ce987, 0xfc9d71844a6250c8, 0x612436341f08b111}}}, -{{{0xd99d41db874e898d, 0x09fea5f16c07dc20, 0x793d2c67d00f9bbc, 0x46ebe2309e5eff40}}, - {{0x8b6349e31a2d2638, 0x9ddfb7009bd3fd35, 0x7f8bf1b8a3a06ba4, 0x1522aa3178d90445}}, - {{0x2c382f5369614938, 0xdafe409ab72d6d10, 0xe8c83391b646f227, 0x45fe70f50524306c}}}, -{{{0xda4875a6960c0b8c, 0x5b68d076ef0e2f20, 0x07fb51cf3d0b8fd4, 0x428d1623a0e392d4}}, - {{0x62f24920c8951491, 0x05f007c83f630ca2, 0x6fbb45d2f5c9d4b8, 0x16619f6db57a2245}}, - {{0x084f4a4401a308fd, 0xa82219c376a5caac, 0xdeb8de4643d1bc7d, 0x1d81592d60bd38c6}}}, -{{{0xd833d7beec2a4c38, 0x2c9162830acc20ed, 0xe93a47aa92df7581, 0x702d67a3333c4a81}}, - {{0x3a4a369a2f89c8a1, 0x63137a1d7c8de80d, 0xbcac008a78eda015, 0x2cb8b3a5b483b03f}}, - {{0x36e417cbcb1b90a1, 0x33b3ddaa7f11794e, 0x3f510808885bc607, 0x24141dc0e6a8020d}}}, -{{{0x59f73c773fefee9d, 0xb3f1ef89c1cf989d, 0xe35dfb42e02e545f, 0x5766120b47a1b47c}}, - {{0x91925dccbd83157d, 0x3ca1205322cc8094, 0x28e57f183f90d6e4, 0x1a4714cede2e767b}}, - {{0xdb20ba0fb8b6b7ff, 0xb732c3b677511fa1, 0xa92b51c099f02d89, 0x4f3875ad489ca5f1}}}, -{{{0xc7fc762f4932ab22, 0x7ac0edf72f4c3c1b, 0x5f6b55aa9aa895e8, 0x3680274dad0a0081}}, - {{0x79ed13f6ee73eec0, 0xa5c6526d69110bb1, 0xe48928c38603860c, 0x722a1446fd7059f5}}, - {{0xd0959fe9a8cf8819, 0xd0a995508475a99c, 0x6eac173320b09cc5, 0x628ecf04331b1095}}}, -{{{0x98bcb118a9d0ddbc, 0xee449e3408b4802b, 0x87089226b8a6b104, 0x685f349a45c7915d}}, - {{0x9b41acf85c74ccf1, 0xb673318108265251, 0x99c92aed11adb147, 0x7a47d70d34ecb40f}}, - {{0x60a0c4cbcc43a4f5, 0x775c66ca3677bea9, 0xa17aa1752ff8f5ed, 0x11ded9020e01fdc0}}}, -{{{0x890e7809caefe704, 0x8728296de30e8c6c, 0x4c5cd2a392aeb1c9, 0x194263d15771531f}}, - {{0x471f95b03bea93b7, 0x0552d7d43313abd3, 0xbd9370e2e17e3f7b, 0x7b120f1db20e5bec}}, - {{0x17d2fb3d86502d7a, 0xb564d84450a69352, 0x7da962c8a60ed75d, 0x00d0f85b318736aa}}}, -{{{0x978b142e777c84fd, 0xf402644705a8c062, 0xa67ad51be7e612c7, 0x2f7b459698dd6a33}}, - {{0xa6753c1efd7621c1, 0x69c0b4a7445671f5, 0x971f527405b23c11, 0x387bc74851a8c7cd}}, - {{0x81894b4d4a52a9a8, 0xadd93e12f6b8832f, 0x184d8548b61bd638, 0x3f1c62dbd6c9f6cd}}}, -{{{0x2e8f1f0091910c1f, 0xa4df4fe0bff2e12c, 0x60c6560aee927438, 0x6338283facefc8fa}}, - {{0x3fad3e40148f693d, 0x052656e194eb9a72, 0x2f4dcbfd184f4e2f, 0x406f8db1c482e18b}}, - {{0x9e630d2c7f191ee4, 0x4fbf8301bc3ff670, 0x787d8e4e7afb73c4, 0x50d83d5be8f58fa5}}}, -{{{0x85683916c11a1897, 0x2d69a4efe506d008, 0x39af1378f664bd01, 0x65942131361517c6}}, - {{0xc0accf90b4d3b66d, 0xa7059de561732e60, 0x033d1f7870c6b0ba, 0x584161cd26d946e4}}, - {{0xbbf2b1a072d27ca2, 0xbf393c59fbdec704, 0xe98dbbcee262b81e, 0x02eebd0b3029b589}}}, -{{{0x61368756a60dac5f, 0x17e02f6aebabdc57, 0x7f193f2d4cce0f7d, 0x20234a7789ecdcf0}}, - {{0x8765b69f7b85c5e8, 0x6ff0678bd168bab2, 0x3a70e77c1d330f9b, 0x3a5f6d51b0af8e7c}}, - {{0x76d20db67178b252, 0x071c34f9d51ed160, 0xf62a4a20b3e41170, 0x7cd682353cffe366}}}, -{{{0x0be1a45bd887fab6, 0x2a846a32ba403b6e, 0xd9921012e96e6000, 0x2838c8863bdc0943}}, - {{0xa665cd6068acf4f3, 0x42d92d183cd7e3d3, 0x5759389d336025d9, 0x3ef0253b2b2cd8ff}}, - {{0xd16bb0cf4a465030, 0xfa496b4115c577ab, 0x82cfae8af4ab419d, 0x21dcb8a606a82812}}}, -{{{0x5c6004468c9d9fc8, 0x2540096ed42aa3cb, 0x125b4d4c12ee2f9c, 0x0bc3d08194a31dab}}, - {{0x9a8d00fabe7731ba, 0x8203607e629e1889, 0xb2cc023743f3d97f, 0x5d840dbf6c6f678b}}, - {{0x706e380d309fe18b, 0x6eb02da6b9e165c7, 0x57bbba997dae20ab, 0x3a4276232ac196dd}}}, -{{{0x4b42432c8a7084fa, 0x898a19e3dfb9e545, 0xbe9f00219c58e45d, 0x1ff177cea16debd1}}, - {{0x3bf8c172db447ecb, 0x5fcfc41fc6282dbd, 0x80acffc075aa15fe, 0x0770c9e824e1a9f9}}, - {{0xcf61d99a45b5b5fd, 0x860984e91b3a7924, 0xe7300919303e3e89, 0x39f264fd41500b1e}}}, -{{{0xa7ad3417dbe7e29c, 0xbd94376a2b9c139c, 0xa0e91b8e93597ba9, 0x1712d73468889840}}, - {{0xd19b4aabfe097be1, 0xa46dfce1dfe01929, 0xc3c908942ca6f1ff, 0x65c621272c35f14e}}, - {{0xe72b89f8ce3193dd, 0x4d103356a125c0bb, 0x0419a93d2e1cfe83, 0x22f9800ab19ce272}}}, -{{{0x605a368a3e9ef8cb, 0xe3e9c022a5504715, 0x553d48b05f24248f, 0x13f416cd647626e5}}, - {{0x42029fdd9a6efdac, 0xb912cebe34a54941, 0x640f64b987bdf37b, 0x4171a4d38598cab4}}, - {{0xfa2758aa99c94c8c, 0x23006f6fb000b807, 0xfbd291ddadda5392, 0x508214fa574bd1ab}}}, -{{{0xc20269153ed6fe4b, 0xa65a6739511d77c4, 0xcbde26462c14af94, 0x22f960ec6faba74b}}, - {{0x461a15bb53d003d6, 0xb2102888bcf3c965, 0x27c576756c683a5a, 0x3a7758a4c86cb447}}, - {{0x548111f693ae5076, 0x1dae21df1dfd54a6, 0x12248c90f3115e65, 0x5d9fd15f8de7f494}}}, -{{{0x031408d36d63727f, 0x6a379aefd7c7b533, 0xa9e18fc5ccaee24b, 0x332f35914f8fbed3}}, - {{0x3f244d2aeed7521e, 0x8e3a9028432e9615, 0xe164ba772e9c16d4, 0x3bc187fa47eb98d8}}, - {{0x6d470115ea86c20c, 0x998ab7cb6c46d125, 0xd77832b53a660188, 0x450d81ce906fba03}}}, -{{{0xf8ae4d2ad8453902, 0x7018058ee8db2d1d, 0xaab3995fc7d2c11e, 0x53b16d2324ccca79}}, - {{0x23264d66b2cae0b5, 0x7dbaed33ebca6576, 0x030ebed6f0d24ac8, 0x2a887f78f7635510}}, - {{0x2a23b9e75c012d4f, 0x0c974651cae1f2ea, 0x2fb63273675d70ca, 0x0ba7250b864403f5}}}, -{{{0xbb0d18fd029c6421, 0xbc2d142189298f02, 0x8347f8e68b250e96, 0x7b9f2fe8032d71c9}}, - {{0xdd63589386f86d9c, 0x61699176e13a85a4, 0x2e5111954eaa7d57, 0x32c21b57fb60bdfb}}, - {{0xd87823cd319e0780, 0xefc4cfc1897775c5, 0x4854fb129a0ab3f7, 0x12c49d417238c371}}}, -{{{0x0950b533ffe83769, 0x21861c1d8e1d6bd1, 0xf022d8381302e510, 0x2509200c6391cab4}}, - {{0x09b3a01783799542, 0x626dd08faad5ee3f, 0xba00bceeeb70149f, 0x1421b246a0a444c9}}, - {{0x4aa43a8e8c24a7c7, 0x04c1f540d8f05ef5, 0xadba5e0c0b3eb9dc, 0x2ab5504448a49ce3}}}, -{{{0x2ed227266f0f5dec, 0x9824ee415ed50824, 0x807bec7c9468d415, 0x7093bae1b521e23f}}, - {{0xdc07ac631c5d3afa, 0x58615171f9df8c6c, 0x72a079d89d73e2b0, 0x7301f4ceb4eae15d}}, - {{0x6409e759d6722c41, 0xa674e1cf72bf729b, 0xbc0a24eb3c21e569, 0x390167d24ebacb23}}}, -{{{0x27f58e3bba353f1c, 0x4c47764dbf6a4361, 0xafbbc4e56e562650, 0x07db2ee6aae1a45d}}, - {{0xd7bb054ba2f2120b, 0xe2b9ceaeb10589b7, 0x3fe8bac8f3c0edbe, 0x4cbd40767112cb69}}, - {{0x0b603cc029c58176, 0x5988e3825cb15d61, 0x2bb61413dcf0ad8d, 0x7b8eec6c74183287}}}, -{{{0xe4ca40782cd27cb0, 0xdaf9c323fbe967bd, 0xb29bd34a8ad41e9e, 0x72810497626ede4d}}, - {{0x32fee570fc386b73, 0xda8b0141da3a8cc7, 0x975ffd0ac8968359, 0x6ee809a1b132a855}}, - {{0x9444bb31fcfd863a, 0x2fe3690a3e4e48c5, 0xdc29c867d088fa25, 0x13bd1e38d173292e}}}, -{{{0xd32b4cd8696149b5, 0xe55937d781d8aab7, 0x0bcb2127ae122b94, 0x41e86fcfb14099b0}}, - {{0x223fb5cf1dfac521, 0x325c25316f554450, 0x030b98d7659177ac, 0x1ed018b64f88a4bd}}, - {{0x3630dfa1b802a6b0, 0x880f874742ad3bd5, 0x0af90d6ceec5a4d4, 0x746a247a37cdc5d9}}}, -{{{0xd531b8bd2b7b9af6, 0x5005093537fc5b51, 0x232fcf25c593546d, 0x20a365142bb40f49}}, - {{0x6eccd85278d941ed, 0x2254ae83d22f7843, 0xc522d02e7bbfcdb7, 0x681e3351bff0e4e2}}, - {{0x8b64b59d83034f45, 0x2f8b71f21fa20efb, 0x69249495ba6550e4, 0x539ef98e45d5472b}}}, -{{{0x6e7bb6a1a6205275, 0xaa4f21d7413c8e83, 0x6f56d155e88f5cb2, 0x2de25d4ba6345be1}}, - {{0xd074d8961cae743f, 0xf86d18f5ee1c63ed, 0x97bdc55be7f4ed29, 0x4cbad279663ab108}}, - {{0x80d19024a0d71fcd, 0xc525c20afb288af8, 0xb1a3974b5f3a6419, 0x7d7fbcefe2007233}}}, -{{{0xfaef1e6a266b2801, 0x866c68c4d5739f16, 0xf68a2fbc1b03762c, 0x5975435e87b75a8d}}, - {{0xcd7c5dc5f3c29094, 0xc781a29a2a9105ab, 0x80c61d36421c3058, 0x4f9cd196dcd8d4d7}}, - {{0x199297d86a7b3768, 0xd0d058241ad17a63, 0xba029cad5c1c0c17, 0x7ccdd084387a0307}}}, -{{{0xdca6422c6d260417, 0xae153d50948240bd, 0xa9c0c1b4fb68c677, 0x428bd0ed61d0cf53}}, - {{0x9b0c84186760cc93, 0xcdae007a1ab32a99, 0xa88dec86620bda18, 0x3593ca848190ca44}}, - {{0x9213189a5e849aa7, 0xd4d8c33565d8facd, 0x8c52545b53fdbbd1, 0x27398308da2d63e6}}}, -{{{0x42c38d28435ed413, 0xbd50f3603278ccc9, 0xbb07ab1a79da03ef, 0x269597aebe8c3355}}, - {{0xb9a10e4c0a702453, 0x0fa25866d57d1bde, 0xffb9d9b5cd27daf7, 0x572c2945492c33fd}}, - {{0xc77fc745d6cd30be, 0xe4dfe8d3e3baaefb, 0xa22c8830aa5dda0c, 0x7f985498c05bca80}}}, -{{{0x3849ce889f0be117, 0x8005ad1b7b54a288, 0x3da3c39f23fc921c, 0x76c2ec470a31f304}}, - {{0xd35615520fbf6363, 0x08045a45cf4dfba6, 0xeec24fbc873fa0c2, 0x30f2653cd69b12e7}}, - {{0x8a08c938aac10c85, 0x46179b60db276bcb, 0xa920c01e0e6fac70, 0x2f1273f1596473da}}}, -{{{0x4739fc7c8ae01e11, 0xfd5274904a6aab9f, 0x41d98a8287728f2e, 0x5d9e572ad85b69f2}}, - {{0x30488bd755a70bc0, 0x06d6b5a4f1d442e7, 0xead1a69ebc596162, 0x38ac1997edc5f784}}, - {{0x0666b517a751b13b, 0x747d06867e9b858c, 0xacacc011454dde49, 0x22dfcd9cbfe9e69c}}}, -{{{0x8ddbd2e0c30d0cd9, 0xad8e665facbb4333, 0x8f6b258c322a961f, 0x6b2916c05448c1c7}}, - {{0x56ec59b4103be0a1, 0x2ee3baecd259f969, 0x797cb29413f5cd32, 0x0fe9877824cde472}}, - {{0x7edb34d10aba913b, 0x4ea3cd822e6dac0e, 0x66083dff6578f815, 0x4c303f307ff00a17}}}, -{{{0xd30a3bd617b28c85, 0xc5d377b739773bea, 0xc6c6e78c1e6a5cbf, 0x0d61b8f78b2ab7c4}}, - {{0x29fc03580dd94500, 0xecd27aa46fbbec93, 0x130a155fc2e2a7f8, 0x416b151ab706a1d5}}, - {{0x56a8d7efe9c136b0, 0xbd07e5cd58e44b20, 0xafe62fda1b57e0ab, 0x191a2af74277e8d2}}}, -{{{0xd550095bab6f4985, 0x04f4cd5b4fbfaf1a, 0x9d8e2ed12a0c7540, 0x2bc24e04b2212286}}, - {{0x09d4b60b2fe09a14, 0xc384f0afdbb1747e, 0x58e2ea8978b5fd6e, 0x519ef577b5e09b0a}}, - {{0x1863d7d91124cca9, 0x7ac08145b88a708e, 0x2bcd7309857031f5, 0x62337a6e8ab8fae5}}}, -{{{0x4bcef17f06ffca16, 0xde06e1db692ae16a, 0x0753702d614f42b0, 0x5f6041b45b9212d0}}, - {{0xd1ab324e1b3a1273, 0x18947cf181055340, 0x3b5d9567a98c196e, 0x7fa00425802e1e68}}, - {{0x7d531574028c2705, 0x80317d69db0d75fe, 0x30fface8ef8c8ddd, 0x7e9de97bb6c3e998}}}, -{{{0x1558967b9e6585a3, 0x97c99ce098e98b92, 0x10af149b6eb3adad, 0x42181fe8f4d38cfa}}, - {{0xf004be62a24d40dd, 0xba0659910452d41f, 0x81c45ee162a44234, 0x4cb829d8a22266ef}}, - {{0x1dbcaa8407b86681, 0x081f001e8b26753b, 0x3cd7ce6a84048e81, 0x78af11633f25f22c}}}, -{{{0x8416ebd40b50babc, 0x1508722628208bee, 0xa3148fafb9c1c36d, 0x0d07daacd32d7d5d}}, - {{0x3241c00e7d65318c, 0xe6bee5dcd0e86de7, 0x118b2dc2fbc08c26, 0x680d04a7fc603dc3}}, - {{0xf9c2414a695aa3eb, 0xdaa42c4c05a68f21, 0x7c6c23987f93963e, 0x210e8cd30c3954e3}}}, -{{{0xac4201f210a71c06, 0x6a65e0aef3bfb021, 0xbc42c35c393632f7, 0x56ea8db1865f0742}}, - {{0x2b50f16137fe6c26, 0xe102bcd856e404d8, 0x12b0f1414c561f6b, 0x51b17bc8d028ec91}}, - {{0xfff5fb4bcf535119, 0xf4989d79df1108a0, 0xbdfcea659a3ba325, 0x18a11f1174d1a6f2}}}, -{{{0x407375ab3f6bba29, 0x9ec3b6d8991e482e, 0x99c80e82e55f92e9, 0x307c13b6fb0c0ae1}}, - {{0xfbd63cdad27a5f2c, 0xf00fc4bc8aa106d7, 0x53fb5c1a8e64a430, 0x04eaabe50c1a2e85}}, - {{0x24751021cb8ab5e7, 0xfc2344495c5010eb, 0x5f1e717b4e5610a1, 0x44da5f18c2710cd5}}}, -{{{0x033cc55ff1b82eb5, 0xb15ae36d411cae52, 0xba40b6198ffbacd3, 0x768edce1532e861f}}, - {{0x9156fe6b89d8eacc, 0xe6b79451e23126a1, 0xbd7463d93944eb4e, 0x726373f6767203ae}}, - {{0xe305ca72eb7ef68a, 0x662cf31f70eadb23, 0x18f026fdb4c45b68, 0x513b5384b5d2ecbd}}}, -{{{0x46d46280c729989e, 0x4b93fbd05368a5dd, 0x63df3f81d1765a89, 0x34cebd64b9a0a223}}, - {{0x5e2702878af34ceb, 0x900b0409b946d6ae, 0x6512ebf7dabd8512, 0x61d9b76988258f81}}, - {{0xa6c5a71349b7d94b, 0xa3f3d15823eb9446, 0x0416fbd277484834, 0x69d45e6f2c70812f}}}, -{{{0xce16f74bc53c1431, 0x2b9725ce2072edde, 0xb8b9c36fb5b23ee7, 0x7e2e0e450b5cc908}}, - {{0x9fe62b434f460efb, 0xded303d4a63607d6, 0xf052210eb7a0da24, 0x237e7dbe00545b93}}, - {{0x013575ed6701b430, 0x231094e69f0bfd10, 0x75320f1583e47f22, 0x71afa699b11155e3}}}, -{{{0x65ce6f9b3953b61d, 0xc65839eaafa141e6, 0x0f435ffda9f759fe, 0x021142e9c2b1c28e}}, - {{0xea423c1c473b50d6, 0x51e87a1f3b38ef10, 0x9b84bf5fb2c9be95, 0x00731fbc78f89a1c}}, - {{0xe430c71848f81880, 0xbf960c225ecec119, 0xb6dae0836bba15e3, 0x4c4d6f3347e15808}}}, -{{{0x18f7eccfc17d1fc9, 0x6c75f5a651403c14, 0xdbde712bf7ee0cdf, 0x193fddaaa7e47a22}}, - {{0x2f0cddfc988f1970, 0x6b916227b0b9f51b, 0x6ec7b6c4779176be, 0x38bf9500a88f9fa8}}, - {{0x1fd2c93c37e8876f, 0xa2f61e5a18d1462c, 0x5080f58239241276, 0x6a6fb99ebf0d4969}}}, -{{{0x6a46c1bb560855eb, 0x2416bb38f893f09d, 0xd71d11378f71acc1, 0x75f76914a31896ea}}, - {{0xeeb122b5b6e423c6, 0x939d7010f286ff8e, 0x90a92a831dcf5d8c, 0x136fda9f42c5eb10}}, - {{0xf94cdfb1a305bdd1, 0x0f364b9d9ff82c08, 0x2a87d8a5c3bb588a, 0x022183510be8dcba}}}, -{{{0x4af766385ead2d14, 0xa08ed880ca7c5830, 0x0d13a6e610211e3d, 0x6a071ce17b806c03}}, - {{0x9d5a710143307a7f, 0xb063de9ec47da45f, 0x22bbfe52be927ad3, 0x1387c441fd40426c}}, - {{0xb5d3c3d187978af8, 0x722b5a3d7f0e4413, 0x0d7b4848bb477ca0, 0x3171b26aaf1edc92}}}, -{{{0xa92f319097564ca8, 0xff7bb84c2275e119, 0x4f55fe37a4875150, 0x221fd4873cf0835a}}, - {{0xa60db7d8b28a47d1, 0xa6bf14d61770a4f1, 0xd4a1f89353ddbd58, 0x6c514a63344243e9}}, - {{0x2322204f3a156341, 0xfb73e0e9ba0a032d, 0xfce0dd4c410f030e, 0x48daa596fb924aaa}}}, -{{{0x6eca8e665ca59cc7, 0xa847254b2e38aca0, 0x31afc708d21e17ce, 0x676dd6fccad84af7}}, - {{0x14f61d5dc84c9793, 0x9941f9e3ef418206, 0xcdf5b88f346277ac, 0x58c837fa0e8a79a9}}, - {{0x0cf9688596fc9058, 0x1ddcbbf37b56a01b, 0xdcc2e77d4935d66a, 0x1c4f73f2c6a57f0a}}}, -{{{0x0e7a4fbd305fa0bb, 0x829d4ce054c663ad, 0xf421c3832fe33848, 0x795ac80d1bf64c42}}, - {{0xb36e706efc7c3484, 0x73dfc9b4c3c1cf61, 0xeb1d79c9781cc7e5, 0x70459adb7daf675c}}, - {{0x1b91db4991b42bb3, 0x572696234b02dcca, 0x9fdf9ee51f8c78dc, 0x5fe162848ce21fd3}}}, -{{{0xe2790aae4d077c41, 0x8b938270db7469a3, 0x6eb632dc8abd16a2, 0x720814ecaa064b72}}, - {{0x315c29c795115389, 0xd7e0e507862f74ce, 0x0c4a762185927432, 0x72de6c984a25a1e4}}, - {{0xae9ab553bf6aa310, 0x050a50a9806d6e1b, 0x92bb7403adff5139, 0x0394d27645be618b}}}, -{{{0x4d572251857eedf4, 0xe3724edde19e93c5, 0x8a71420e0b797035, 0x3b3c833687abe743}}, - {{0xf5396425b23545a4, 0x15a7a27e98fbb296, 0xab6c52bc636fdd86, 0x79d995a8419334ee}}, - {{0xcd8a8ea61195dd75, 0xa504d8a81dd9a82f, 0x540dca81a35879b6, 0x60dd16a379c86a8a}}}, -{{{0x35a2c8487381e559, 0x596ffea6d78082cb, 0xcb9771ebdba7b653, 0x5a08b5019b4da685}}, - {{0x3501d6f8153e47b8, 0xb7a9675414a2f60c, 0x112ee8b6455d9523, 0x4e62a3c18112ea8a}}, - {{0xc8d4ac04516ab786, 0x595af3215295b23d, 0xd6edd234db0230c1, 0x0929efe8825b41cc}}}, -{{{0x5f0601d1cbd0f2d3, 0x736e412f6132bb7f, 0x83604432238dde87, 0x1e3a5272f5c0753c}}, - {{0x8b3172b7ad56651d, 0x01581b7a3fabd717, 0x2dc94df6424df6e4, 0x30376e5d2c29284f}}, - {{0xd2918da78159a59c, 0x6bdc1cd93f0713f3, 0x565f7a934acd6590, 0x53daacec4cb4c128}}}, -{{{0x4ca73bd79cc8a7d6, 0x4d4a738f47e9a9b2, 0xf4cbf12942f5fe00, 0x01a13ff9bdbf0752}}, - {{0x99852bc3852cfdb0, 0x2cc12e9559d6ed0b, 0x70f9e2bf9b5ac27b, 0x4f3b8c117959ae99}}, - {{0x55b6c9c82ff26412, 0x1ac4a8c91fb667a8, 0xd527bfcfeb778bf2, 0x303337da7012a3be}}}, -{{{0x955422228c1c9d7c, 0x01fac1371a9b340f, 0x7e8d9177925b48d7, 0x53f8ad5661b3e31b}}, - {{0x976d3ccbfad2fdd1, 0xcb88839737a640a8, 0x2ff00c1d6734cb25, 0x269ff4dc789c2d2b}}, - {{0x0c003fbdc08d678d, 0x4d982fa37ead2b17, 0xc07e6bcdb2e582f1, 0x296c7291df412a44}}}, -{{{0x7903de2b33daf397, 0xd0ff0619c9a624b3, 0x8a1d252b555b3e18, 0x2b6d581c52e0b7c0}}, - {{0xdfb23205dab8b59e, 0x465aeaa0c8092250, 0xd133c1189a725d18, 0x2327370261f117d1}}, - {{0x3d0543d3623e7986, 0x679414c2c278a354, 0xae43f0cc726196f6, 0x7836c41f8245eaba}}}, -{{{0xe7a254db49e95a81, 0x5192d5d008b0ad73, 0x4d20e5b1d00afc07, 0x5d55f8012cf25f38}}, - {{0xca651e848011937c, 0xc6b0c46e6ef41a28, 0xb7021ba75f3f8d52, 0x119dff99ead7b9fd}}, - {{0x43eadfcbf4b31d4d, 0xc6503f7411148892, 0xfeee68c5060d3b17, 0x329293b3dd4a0ac8}}}, -{{{0x4e59214fe194961a, 0x49be7dc70d71cd4f, 0x9300cfd23b50f22d, 0x4789d446fc917232}}, - {{0x2879852d5d7cb208, 0xb8dedd70687df2e7, 0xdc0bffab21687891, 0x2b44c043677daa35}}, - {{0x1a1c87ab074eb78e, 0xfac6d18e99daf467, 0x3eacbbcd484f9067, 0x60c52eef2bb9a4e4}}}, -{{{0x0b5d89bc3bfd8bf1, 0xb06b9237c9f3551a, 0x0e4c16b0d53028f5, 0x10bc9c312ccfcaab}}, - {{0x702bc5c27cae6d11, 0x44c7699b54a48cab, 0xefbc4056ba492eb2, 0x70d77248d9b6676d}}, - {{0xaa8ae84b3ec2a05b, 0x98699ef4ed1781e0, 0x794513e4708e85d1, 0x63755bd3a976f413}}}, -{{{0xb55fa03e2ad10853, 0x356f75909ee63569, 0x9ff9f1fdbe69b890, 0x0d8cc1c48bc16f84}}, - {{0x3dc7101897f1acb7, 0x5dda7d5ec165bbd8, 0x508e5b9c0fa1020f, 0x2763751737c52a56}}, - {{0x029402d36eb419a9, 0xf0b44e7e77b460a5, 0xcfa86230d43c4956, 0x70c2dd8a7ad166e7}}}, -{{{0x656194509f6fec0e, 0xee2e7ea946c6518d, 0x9733c1f367e09b5c, 0x2e0fac6363948495}}, - {{0x91d4967db8ed7e13, 0x74252f0ad776817a, 0xe40982e00d852564, 0x32b8613816a53ce5}}, - {{0x79e7f7bee448cd64, 0x6ac83a67087886d0, 0xf89fd4d9a0e4db2e, 0x4179215c735a4f41}}}, -{{{0x8c7094e7d7dced2a, 0x97fb8ac347d39c70, 0xe13be033a906d902, 0x700344a30cd99d76}}, - {{0xe4ae33b9286bcd34, 0xb7ef7eb6559dd6dc, 0x278b141fb3d38e1f, 0x31fa85662241c286}}, - {{0xaf826c422e3622f4, 0xc12029879833502d, 0x9bc1b7e12b389123, 0x24bb2312a9952489}}}, -{{{0xb1a8ed1732de67c3, 0x3cb49418461b4948, 0x8ebd434376cfbcd2, 0x0fee3e871e188008}}, - {{0x41f80c2af5f85c6b, 0x687284c304fa6794, 0x8945df99a3ba1bad, 0x0d1d2af9ffeb5d16}}, - {{0xa9da8aa132621edf, 0x30b822a159226579, 0x4004197ba79ac193, 0x16acd79718531d76}}}, -{{{0x72df72af2d9b1d3d, 0x63462a36a432245a, 0x3ecea07916b39637, 0x123e0ef6b9302309}}, - {{0xc959c6c57887b6ad, 0x94e19ead5f90feba, 0x16e24e62a342f504, 0x164ed34b18161700}}, - {{0x487ed94c192fe69a, 0x61ae2cea3a911513, 0x877bf6d3b9a4de27, 0x78da0fc61073f3eb}}}, -{{{0x5bf15d28e52bc66a, 0x2c47e31870f01a8e, 0x2419afbc06c28bdd, 0x2d25deeb256b173a}}, - {{0xa29f80f1680c3a94, 0x71f77e151ae9e7e6, 0x1100f15848017973, 0x054aa4b316b38ddd}}, - {{0xdfc8468d19267cb8, 0x0b28789c66e54daf, 0x2aeb1d2a666eec17, 0x134610a6ab7da760}}}, -{{{0xcaf55ec27c59b23f, 0x99aeed3e154d04f2, 0x68441d72e14141f4, 0x140345133932a0a2}}, - {{0xd91430e0dc028c3c, 0x0eb955a85217c771, 0x4b09e1ed2c99a1fa, 0x42881af2bd6a743c}}, - {{0x7bfec69aab5cad3d, 0xc23e8cd34cb2cfad, 0x685dd14bfb37d6a2, 0x0ad6d64415677a18}}}, -{{{0x781a439e417becb5, 0x4ac5938cd10e0266, 0x5da385110692ac24, 0x11b065a2ade31233}}, - {{0x7914892847927e9f, 0x33dad6ef370aa877, 0x1f8f24fa11122703, 0x5265ac2f2adf9592}}, - {{0x405fdd309afcb346, 0xd9723d4428e63f54, 0x94c01df05f65aaae, 0x43e4dc3ae14c0809}}}, -{{{0xbc12c7f1a938a517, 0x473028ab3180b2e1, 0x3f78571efbcd254a, 0x74e534426ff6f90f}}, - {{0xea6f7ac3adc2c6a3, 0xd0e928f6e9717c94, 0xe2d379ead645eaf5, 0x46dd8785c51ffbbe}}, - {{0x709801be375c8898, 0x4b06dab5e3fd8348, 0x75880ced27230714, 0x2b09468fdd2f4c42}}}, -{{{0x97c749eeb701cb96, 0x83f438d4b6a369c3, 0x62962b8b9a402cd9, 0x6976c7509888df7b}}, - {{0x5b97946582ffa02a, 0xda096a51fea8f549, 0xa06351375f77af9b, 0x1bcfde61201d1e76}}, - {{0x4a4a5490246a59a2, 0xd63ebddee87fdd90, 0xd9437c670d2371fa, 0x69e87308d30f8ed6}}}, -{{{0x435a8bb15656beb0, 0xf8fac9ba4f4d5bca, 0xb9b278c41548c075, 0x3eb0ef76e892b622}}, - {{0x0f80bf028bc80303, 0x6aae16b37a18cefb, 0xdd47ea47d72cd6a3, 0x61943588f4ed39aa}}, - {{0xd26e5c3e91039f85, 0xc0e9e77df6f33aa9, 0xe8968c5570066a93, 0x3c34d1881faaaddd}}}, -{{{0x3f9d2b5ea09f9ec0, 0x1dab3b6fb623a890, 0xa09ba3ea72d926c4, 0x374193513fd8b36d}}, - {{0xbd5b0b8f2fffe0d9, 0x6aa254103ed24fb9, 0x2ac7d7bcb26821c4, 0x605b394b60dca36a}}, - {{0xb4e856e45a9d1ed2, 0xefe848766c97a9a2, 0xb104cf641e5eee7d, 0x2f50b81c88a71c8f}}}, -{{{0x31723c61fc6811bb, 0x9cb450486211800f, 0x768933d347995753, 0x3491a53502752fcd}}, - {{0x2b552ca0a7da522a, 0x3230b336449b0250, 0xf2c4c5bca4b99fb9, 0x7b2c674958074a22}}, - {{0xd55165883ed28cdf, 0x12d84fd2d362de39, 0x0a874ad3e3378e4f, 0x000d2b1f7c763e74}}}, -{{{0x3d420811d06d4a67, 0xbefc048590e0ffe3, 0xf870c6b7bd487bde, 0x6e2a7316319afa28}}, - {{0x9624778c3e94a8ab, 0x0ad6f3cee9a78bec, 0x948ac7810d743c4f, 0x76627935aaecfccc}}, - {{0x56a8ac24d6d59a9f, 0xc8db753e3096f006, 0x477f41e68f4c5299, 0x588d851cf6c86114}}}, -{{{0x51138ec78df6b0fe, 0x5397da89e575f51b, 0x09207a1d717af1b9, 0x2102fdba2b20d650}}, - {{0xcd2a65e777d1f515, 0x548991878faa60f1, 0xb1b73bbcdabc06e5, 0x654878cba97cc9fb}}, - {{0x969ee405055ce6a1, 0x36bca7681251ad29, 0x3a1af517aa7da415, 0x0ad725db29ecb2ba}}}, -{{{0xdc4267b1834e2457, 0xb67544b570ce1bc5, 0x1af07a0bf7d15ed7, 0x4aefcffb71a03650}}, - {{0xfec7bc0c9b056f85, 0x537d5268e7f5ffd7, 0x77afc6624312aefa, 0x4f675f5302399fd9}}, - {{0xc32d36360415171e, 0xcd2bef118998483b, 0x870a6eadd0945110, 0x0bccbb72a2a86561}}}, -{{{0x185e962feab1a9c8, 0x86e7e63565147dcd, 0xb092e031bb5b6df2, 0x4024f0ab59d6b73e}}, - {{0x186d5e4c50fe1296, 0xe0397b82fee89f7e, 0x3bc7f6c5507031b0, 0x6678fd69108f37c2}}, - {{0x1586fa31636863c2, 0x07f68c48572d33f2, 0x4f73cc9f789eaefc, 0x2d42e2108ead4701}}}, -{{{0x97f5131594dfd29b, 0x6155985d313f4c6a, 0xeba13f0708455010, 0x676b2608b8d2d322}}, - {{0x21717b0d0f537593, 0x914e690b131e064c, 0x1bb687ae752ae09f, 0x420bf3a79b423c6e}}, - {{0x8138ba651c5b2b47, 0x8671b6ec311b1b80, 0x7bff0cb1bc3135b0, 0x745d2ffa9c0cf1e0}}}, -{{{0xbf525a1e2bc9c8bd, 0xea5b260826479d81, 0xd511c70edf0155db, 0x1ae23ceb960cf5d0}}, - {{0x6036df5721d34e6a, 0xb1db8827997bb3d0, 0xd3c209c3c8756afa, 0x06e15be54c1dc839}}, - {{0x5b725d871932994a, 0x32351cb5ceb1dab0, 0x7dc41549dab7ca05, 0x58ded861278ec1f7}}}, -{{{0xd8173793f266c55c, 0xc8c976c5cc454e49, 0x5ce382f8bc26c3a8, 0x2ff39de85485f6f9}}, - {{0x2dfb5ba8b6c2c9a8, 0x48eeef8ef52c598c, 0x33809107f12d1573, 0x08ba696b531d5bd8}}, - {{0x77ed3eeec3efc57a, 0x04e05517d4ff4811, 0xea3d7a3ff1a671cb, 0x120633b4947cfe54}}}, -{{{0x0b94987891610042, 0x4ee7b13cecebfae8, 0x70be739594f0a4c0, 0x35d30a99b4d59185}}, - {{0x82bd31474912100a, 0xde237b6d7e6fbe06, 0xe11e761911ea79c6, 0x07433be3cb393bde}}, - {{0xff7944c05ce997f4, 0x575d3de4b05c51a3, 0x583381fd5a76847c, 0x2d873ede7af6da9f}}}, -{{{0x157a316443373409, 0xfab8b7eef4aa81d9, 0xb093fee6f5a64806, 0x2e773654707fa7b6}}, - {{0xaa6202e14e5df981, 0xa20d59175015e1f5, 0x18a275d3bae21d6c, 0x0543618a01600253}}, - {{0x0deabdf4974c23c1, 0xaa6f0a259dce4693, 0x04202cb8a29aba2c, 0x4b1443362d07960d}}}, -{{{0x47b837f753242cec, 0x256dc48cc04212f2, 0xe222fbfbe1d928c5, 0x48ea295bad8a2c07}}, - {{0x299b1c3f57c5715e, 0x96cb929e6b686d90, 0x3004806447235ab3, 0x2c435c24a44d9fe1}}, - {{0x0607c97c80f8833f, 0x0e851578ca25ec5b, 0x54f7450b161ebb6f, 0x7bcb4792a0def80e}}}, -{{{0x8487e3d02bc73659, 0x4baf8445059979df, 0xd17c975adcad6fbf, 0x57369f0bdefc96b6}}, - {{0x1cecd0a0045224c2, 0x757f1b1b69e53952, 0x775b7a925289f681, 0x1b6cc62016736148}}, - {{0xf1a9990175638698, 0x353dd1beeeaa60d3, 0x849471334c9ba488, 0x63fa6e6843ade311}}}, -{{{0xd15c20536597c168, 0x9f73740098d28789, 0x18aee7f13257ba1f, 0x3418bfda07346f14}}, - {{0x2195becdd24b5eb7, 0x5e41f18cc0cd44f9, 0xdf28074441ca9ede, 0x07073b98f35b7d67}}, - {{0xd03c676c4ce530d4, 0x0b64c0473b5df9f4, 0x065cef8b19b3a31e, 0x3084d661533102c9}}}, -{{{0xe1f6b79ebf8469ad, 0x15801004e2663135, 0x9a498330af74181b, 0x3ba2504f049b673c}}, - {{0x9a6ce876760321fd, 0x7fe2b5109eb63ad8, 0x00e7d4ae8ac80592, 0x73d86b7abb6f723a}}, - {{0x0b52b5606dba5ab6, 0xa9134f0fbbb1edab, 0x30a9520d9b04a635, 0x6813b8f37973e5db}}}, -{{{0x9854b054334127c1, 0x105d047882fbff25, 0xdb49f7f944186f4f, 0x1768e838bed0b900}}, - {{0xf194ca56f3157e29, 0x136d35705ef528a5, 0xdd4cef778b0599bc, 0x7d5472af24f833ed}}, - {{0xd0ef874daf33da47, 0x00d3be5db6e339f9, 0x3f2a8a2f9c9ceece, 0x5d1aeb792352435a}}}, -{{{0xf59e6bb319cd63ca, 0x670c159221d06839, 0xb06d565b2150cab6, 0x20fb199d104f12a3}}, - {{0x12c7bfaeb61ba775, 0xb84e621fe263bffd, 0x0b47a5c35c840dcf, 0x7e83be0bccaf8634}}, - {{0x61943dee6d99c120, 0x86101f2e460b9fe0, 0x6bb2f1518ee8598d, 0x76b76289fcc475cc}}}, -{{{0x791b4cc1756286fa, 0xdbced317d74a157c, 0x7e732421ea72bde6, 0x01fe18491131c8e9}}, - {{0x4245f1a1522ec0b3, 0x558785b22a75656d, 0x1d485a2548a1b3c0, 0x60959eccd58fe09f}}, - {{0x3ebfeb7ba8ed7a09, 0x49fdc2bbe502789c, 0x44ebce5d3c119428, 0x35e1eb55be947f4a}}}, -{{{0xdbdae701c5738dd3, 0xf9c6f635b26f1bee, 0x61e96a8042f15ef4, 0x3aa1d11faf60a4d8}}, - {{0x14fd6dfa726ccc74, 0x3b084cfe2f53b965, 0xf33ae4f552a2c8b4, 0x59aab07a0d40166a}}, - {{0x77bcec4c925eac25, 0x1848718460137738, 0x5b374337fea9f451, 0x1865e78ec8e6aa46}}}, -{{{0xccc4b7c7b66e1f7a, 0x44157e25f50c2f7e, 0x3ef06dfc713eaf1c, 0x582f446752da63f7}}, - {{0x967c54e91c529ccb, 0x30f6269264c635fb, 0x2747aff478121965, 0x17038418eaf66f5c}}, - {{0xc6317bd320324ce4, 0xa81042e8a4488bc4, 0xb21ef18b4e5a1364, 0x0c2a1c4bcda28dc9}}}, -{{{0xd24dc7d06f1f0447, 0xb2269e3edb87c059, 0xd15b0272fbb2d28f, 0x7c558bd1c6f64877}}, - {{0xedc4814869bd6945, 0x0d6d907dbe1c8d22, 0xc63bd212d55cc5ab, 0x5a6a9b30a314dc83}}, - {{0xd0ec1524d396463d, 0x12bb628ac35a24f0, 0xa50c3a791cbc5fa4, 0x0404a5ca0afbafc3}}}, -{{{0x8c1f40070aa743d6, 0xccbad0cb5b265ee8, 0x574b046b668fd2de, 0x46395bfdcadd9633}}, - {{0x62bc9e1b2a416fd1, 0xb5c6f728e350598b, 0x04343fd83d5d6967, 0x39527516e7f8ee98}}, - {{0x117fdb2d1a5d9a9c, 0x9c7745bcd1005c2a, 0xefd4bef154d56fea, 0x76579a29e822d016}}}, -{{{0x45b68e7e49c02a17, 0x23cd51a2bca9a37f, 0x3ed65f11ec224c1b, 0x43a384dc9e05bdb1}}, - {{0x333cb51352b434f2, 0xd832284993de80e1, 0xb5512887750d35ce, 0x02c514bb2a2777c1}}, - {{0x684bd5da8bf1b645, 0xfb8bd37ef6b54b53, 0x313916d7a9b0d253, 0x1160920961548059}}}, -{{{0xb44d166929dacfaa, 0xda529f4c8413598f, 0xe9ef63ca453d5559, 0x351e125bc5698e0b}}, - {{0x7a385616369b4dcd, 0x75c02ca7655c3563, 0x7dc21bf9d4f18021, 0x2f637d7491e6e042}}, - {{0xd4b49b461af67bbe, 0xd603037ac8ab8961, 0x71dee19ff9a699fb, 0x7f182d06e7ce2a9a}}}, -{{{0x7a7c8e64ab0168ec, 0xcb5a4a5515edc543, 0x095519d347cd0eda, 0x67d4ac8c343e93b0}}, - {{0x09454b728e217522, 0xaa58e8f4d484b8d8, 0xd358254d7f46903c, 0x44acc043241c5217}}, - {{0x1c7d6bbb4f7a5777, 0x8b35fed4918313e1, 0x4adca1c6c96b4684, 0x556d1c8312ad71bd}}}, -{{{0x17ef40e30c8d3982, 0x31f7073e15a3fa34, 0x4f21f3cb0773646e, 0x746c6c6d1d824eff}}, - {{0x81f06756b11be821, 0x0faff82310a3f3dd, 0xf8b2d0556a99465d, 0x097abe38cc8c7f05}}, - {{0x0c49c9877ea52da4, 0x4c4369559bdc1d43, 0x022c3809f7ccebd2, 0x577e14a34bee84bd}}}, -{{{0xf0e268ac61a73b0a, 0xf2fafa103791a5f5, 0xc1e13e826b6d00e9, 0x60fa7ee96fd78f42}}, - {{0x94fecebebd4dd72b, 0xf46a4fda060f2211, 0x124a5977c0c8d1ff, 0x705304b8fb009295}}, - {{0xb63d1d354d296ec6, 0xf3c3053e5fad31d8, 0x670b958cb4bd42ec, 0x21398e0ca16353fd}}}, -{{{0x216ab2ca8da7d2ef, 0x366ad9dd99f42827, 0xae64b9004fdd3c75, 0x403a395b53909e62}}, - {{0x86c5fc16861b7e9a, 0xf6a330476a27c451, 0x01667267a1e93597, 0x05ffb9cd6082dfeb}}, - {{0xa617fa9ff53f6139, 0x60f2b5e513e66cb6, 0xd7a8beefb3448aa4, 0x7a2932856f5ea192}}}, -{{{0x0b39d761b02de888, 0x5f550e7ed2414e1f, 0xa6bfa45822e1a940, 0x050a2f7dfd447b99}}, - {{0xb89c444879639302, 0x4ae4f19350c67f2c, 0xf0b35da8c81af9c6, 0x39d0003546871017}}, - {{0x437c3b33a650db77, 0x6bafe81dbac52bb2, 0xfe99402d2db7d318, 0x2b5b7eec372ba6ce}}}, -{{{0xb3bc4bbd83f50eef, 0x508f0c998c927866, 0x43e76587c8b7e66e, 0x0f7655a3a47f98d9}}, - {{0xa694404d613ac8f4, 0x500c3c2bfa97e72c, 0x874104d21fcec210, 0x1b205fb38604a8ee}}, - {{0x55ecad37d24b133c, 0x441e147d6038c90b, 0x656683a1d62c6fee, 0x0157d5dc87e0ecae}}}, -{{{0xf2a7af510354c13d, 0xd7a0b145aa372b60, 0x2869b96a05a3d470, 0x6528e42d82460173}}, - {{0x95265514d71eb524, 0xe603d8815df14593, 0x147cdf410d4de6b7, 0x5293b1730437c850}}, - {{0x23d0e0814bccf226, 0x92c745cd8196fb93, 0x8b61796c59541e5b, 0x40a44df0c021f978}}}, -{{{0xdaa869894f20ea6a, 0xea14a3d14c620618, 0x6001fccb090bf8be, 0x35f4e822947e9cf0}}, - {{0x86c96e514bc5d095, 0xf20d4098fca6804a, 0x27363d89c826ea5d, 0x39ca36565719cacf}}, - {{0x97506f2f6f87b75c, 0xc624aea0034ae070, 0x1ec856e3aad34dd6, 0x055b0be0e440e58f}}}, -{{{0x6469a17d89735d12, 0xdb6f27d5e662b9f1, 0x9fcba3286a395681, 0x363b8004d269af25}}, - {{0x4d12a04b6ea33da2, 0x57cf4c15e36126dd, 0x90ec9675ee44d967, 0x64ca348d2a985aac}}, - {{0x99588e19e4c4912d, 0xefcc3b4e1ca5ce6b, 0x4522ea60fa5b98d5, 0x7064bbab1de4a819}}}, -{{{0xb919e1515a770641, 0xa9a2e2c74e7f8039, 0x7527250b3df23109, 0x756a7330ac27b78b}}, - {{0xa290c06142542129, 0xf2e2c2aebe8d5b90, 0xcf2458db76abfe1b, 0x02157ade83d626bf}}, - {{0x3e46972a1b9a038b, 0x2e4ee66a7ee03fb4, 0x81a248776edbb4ca, 0x1a944ee88ecd0563}}}, -{{{0xd5a91d1151039372, 0x2ed377b799ca26de, 0xa17202acfd366b6b, 0x0730291bd6901995}}, - {{0xbb40a859182362d6, 0xb99f55778a4d1abb, 0x8d18b427758559f6, 0x26c20fe74d26235a}}, - {{0x648d1d9fe9cc22f5, 0x66bc561928dd577c, 0x47d3ed21652439d1, 0x49d271acedaf8b49}}}, -{{{0x89f5058a382b33f3, 0x5ae2ba0bad48c0b4, 0x8f93b503a53db36e, 0x5aa3ed9d95a232e6}}, - {{0x2798aaf9b4b75601, 0x5eac72135c8dad72, 0xd2ceaa6161b7a023, 0x1bbfb284e98f7d4e}}, - {{0x656777e9c7d96561, 0xcb2b125472c78036, 0x65053299d9506eee, 0x4a07e14e5e8957cc}}}, -{{{0x4ee412cb980df999, 0xa315d76f3c6ec771, 0xbba5edde925c77fd, 0x3f0bac391d313402}}, - {{0x240b58cdc477a49b, 0xfd38dade6447f017, 0x19928d32a7c86aad, 0x50af7aed84afa081}}, - {{0x6e4fde0115f65be5, 0x29982621216109b2, 0x780205810badd6d9, 0x1921a316baebd006}}}, -{{{0x89422f7edfb870fc, 0x2c296beb4f76b3bd, 0x0738f1d436c24df7, 0x6458df41e273aeb0}}, - {{0xd75aad9ad9f3c18b, 0x566a0eef60b1c19c, 0x3e9a0bac255c0ed9, 0x7b049deca062c7f5}}, - {{0xdccbe37a35444483, 0x758879330fedbe93, 0x786004c312c5dd87, 0x6093dccbc2950e64}}}, -{{{0x1ff39a8585e0706d, 0x36d0a5d8b3e73933, 0x43b9f2e1718f453b, 0x57d1ea084827a97c}}, - {{0x6bdeeebe6084034b, 0x3199c2b6780fb854, 0x973376abb62d0695, 0x6e3180c98b647d90}}, - {{0xee7ab6e7a128b071, 0xa4c1596d93a88baa, 0xf7b4de82b2216130, 0x363e999ddd97bd18}}}, -{{{0x96a843c135ee1fc4, 0x976eb35508e4c8cf, 0xb42f6801b58cd330, 0x48ee9b78693a052b}}, - {{0x2f1848dce24baec6, 0x769b7255babcaf60, 0x90cb3c6e3cefe931, 0x231f979bc6f9b355}}, - {{0x5c31de4bcc2af3c6, 0xb04bb030fe208d1f, 0xb78d7009c14fb466, 0x079bfa9b08792413}}}, -{{{0xe3903a51da300df4, 0x843964233da95ab0, 0xed3cf12d0b356480, 0x038c77f684817194}}, - {{0xf3c9ed80a2d54245, 0x0aa08b7877f63952, 0xd76dac63d1085475, 0x1ef4fb159470636b}}, - {{0x854e5ee65b167bec, 0x59590a4296d0cdc2, 0x72b2df3498102199, 0x575ee92a4a0bff56}}}, -{{{0xd4c080908a182fcf, 0x30e170c299489dbd, 0x05babd5752f733de, 0x43d4e7112cd3fd00}}, - {{0x5d46bc450aa4d801, 0xc3af1227a533b9d8, 0x389e3b262b8906c2, 0x200a1e7e382f581b}}, - {{0x518db967eaf93ac5, 0x71bc989b056652c0, 0xfe2b85d9567197f5, 0x050eca52651e4e38}}}, -{{{0xc3431ade453f0c9c, 0xe9f5045eff703b9b, 0xfcd97ac9ed847b3d, 0x4b0ee6c21c58f4c6}}, - {{0x97ac397660e668ea, 0x9b19bbfe153ab497, 0x4cb179b534eca79f, 0x6151c09fa131ae57}}, - {{0x3af55c0dfdf05d96, 0xdd262ee02ab4ee7a, 0x11b2bb8712171709, 0x1fef24fa800f030b}}}, -{{{0xb496123a6b6c6609, 0xa750fe8580ab5938, 0xf471bf39b7c27a5f, 0x507903ce77ac193c}}, - {{0xff91a66a90166220, 0xf22552ae5bf1e009, 0x7dff85d87f90df7c, 0x4f620ffe0c736fb9}}, - {{0x62f90d65dfde3e34, 0xcf28c592b9fa5fad, 0x99c86ef9c6164510, 0x25d448044a256c84}}}, -{{{0xbd68230ec7e9b16f, 0x0eb1b9c1c1c5795d, 0x7943c8c495b6b1ff, 0x2f9faf620bbacf5e}}, - {{0x2c7c4415c9022b55, 0x56a0d241812eb1fe, 0xf02ea1c9d7b65e0d, 0x4180512fd5323b26}}, - {{0xa4ff3e698a48a5db, 0xba6a3806bd95403b, 0x9f7ce1af47d5b65d, 0x15e087e55939d2fb}}}, -{{{0x12207543745c1496, 0xdaff3cfdda38610c, 0xe4e797272c71c34f, 0x39c07b1934bdede9}}, - {{0x8894186efb963f38, 0x48a00e80dc639bd5, 0xa4e8092be96c1c99, 0x5a097d54ca573661}}, - {{0x2d45892b17c9e755, 0xd033fd7289308df8, 0x6c2fe9d9525b8bd9, 0x2edbecf1c11cc079}}}, -{{{0x1616a4e3c715a0d2, 0x53623cb0f8341d4d, 0x96ef5329c7e899cb, 0x3d4e8dbba668baa6}}, - {{0xee0f0fddd087a25f, 0x9c7531555c3e34ee, 0x660c572e8fab3ab5, 0x0854fc44544cd3b2}}, - {{0x61eba0c555edad19, 0x24b533fef0a83de6, 0x3b77042883baa5f8, 0x678f82b898a47e8d}}}, -{{{0xb1491d0bd6900c54, 0x3539722c9d132636, 0x4db928920b362bc9, 0x4d7cd1fea68b69df}}, - {{0x1e09d94057775696, 0xeed1265c3cd951db, 0xfa9dac2b20bce16f, 0x0f7f76e0e8d089f4}}, - {{0x36d9ebc5d485b00c, 0xa2596492e4adb365, 0xc1659480c2119ccd, 0x45306349186e0d5f}}}, -{{{0x94ddd0c1a6cdff1d, 0x55f6f115e84213ae, 0x6c935f85992fcf6a, 0x067ee0f54a37f16f}}, - {{0x96a414ec2b072491, 0x1bb2218127a7b65b, 0x6d2849596e8a4af0, 0x65f3b08ccd27765f}}, - {{0xecb29fff199801f7, 0x9d361d1fa2a0f72f, 0x25f11d2375fd2f49, 0x124cefe80fe10fe2}}}, -{{{0x4c126cf9d18df255, 0xc1d471e9147a63b6, 0x2c6d3c73f3c93b5f, 0x6be3a6a2e3ff86a2}}, - {{0x1518e85b31b16489, 0x8faadcb7db710bfb, 0x39b0bdf4a14ae239, 0x05f4cbea503d20c1}}, - {{0xce040e9ec04145bc, 0xc71ff4e208f6834c, 0xbd546e8dab8847a3, 0x64666aa0a4d2aba5}}}, -{{{0x6841435a7c06d912, 0xca123c21bb3f830b, 0xd4b37b27b1cbe278, 0x1d753b84c76f5046}}, - {{0xb0c53bf73337e94c, 0x7cb5697e11e14f15, 0x4b84abac1930c750, 0x28dd4abfe0640468}}, - {{0x7dc0b64c44cb9f44, 0x18a3e1ace3925dbf, 0x7a3034862d0457c4, 0x4c498bf78a0c892e}}}, -{{{0x37d653fb1aa73196, 0x0f9495303fd76418, 0xad200b09fb3a17b2, 0x544d49292fc8613e}}, - {{0x22d2aff530976b86, 0x8d90b806c2d24604, 0xdca1896c4de5bae5, 0x28005fe6c8340c17}}, - {{0x6aefba9f34528688, 0x5c1bff9425107da1, 0xf75bbbcd66d94b36, 0x72e472930f316dfa}}}, -{{{0x2695208c9781084f, 0xb1502a0b23450ee1, 0xfd9daea603efde02, 0x5a9d2e8c2733a34c}}, - {{0x07f3f635d32a7627, 0x7aaa4d865f6566f0, 0x3c85e79728d04450, 0x1fee7f000fe06438}}, - {{0x765305da03dbf7e5, 0xa4daf2491434cdbd, 0x7b4ad5cdd24a88ec, 0x00f94051ee040543}}}, -{{{0x8d356b23c3d330b2, 0xf21c8b9bb0471b06, 0xb36c316c6e42b83c, 0x07d79c7e8beab10d}}, - {{0xd7ef93bb07af9753, 0x583ed0cf3db766a7, 0xce6998bf6e0b1ec5, 0x47b7ffd25dd40452}}, - {{0x87fbfb9cbc08dd12, 0x8a066b3ae1eec29b, 0x0d57242bdb1fc1bf, 0x1c3520a35ea64bb6}}}, -{{{0x80d253a6bccba34a, 0x3e61c3a13838219b, 0x90c3b6019882e396, 0x1c3d05775d0ee66f}}, - {{0xcda86f40216bc059, 0x1fbb231d12bcd87e, 0xb4956a9e17c70990, 0x38750c3b66d12e55}}, - {{0x692ef1409422e51a, 0xcbc0c73c2b5df671, 0x21014fe7744ce029, 0x0621e2c7d330487c}}}, -{{{0xaf9860cc8259838d, 0x90ea48c1c69f9adc, 0x6526483765581e30, 0x0007d6097bd3a5bc}}, - {{0xb7ae1796b0dbf0f3, 0x54dfafb9e17ce196, 0x25923071e9aaa3b4, 0x5d8e589ca1002e9d}}, - {{0xc0bf1d950842a94b, 0xb2d3c363588f2e3e, 0x0a961438bb51e2ef, 0x1583d7783c1cbf86}}}, -{{{0xeceea2ef5da27ae1, 0x597c3a1455670174, 0xc9a62a126609167a, 0x252a5f2e81ed8f70}}, - {{0x90034704cc9d28c7, 0x1d1b679ef72cc58f, 0x16e12b5fbe5b8726, 0x4958064e83c5580a}}, - {{0x0d2894265066e80d, 0xfcc3f785307c8c6b, 0x1b53da780c1112fd, 0x079c170bd843b388}}}, -{{{0x0506ece464fa6fff, 0xbee3431e6205e523, 0x3579422451b8ea42, 0x6dec05e34ac9fb00}}, - {{0xcdd6cd50c0d5d056, 0x9af7686dbb03573b, 0x3ca6723ff3c3ef48, 0x6768c0d7317b8acc}}, - {{0x94b625e5f155c1b3, 0x417bf3a7997b7b91, 0xc22cbddc6d6b2600, 0x51445e14ddcd52f4}}}, -{{{0x57502b4b3b144951, 0x8e67ff6b444bbcb3, 0xb8bd6927166385db, 0x13186f31e39295c8}}, - {{0x893147ab2bbea455, 0x8c53a24f92079129, 0x4b49f948be30f7a7, 0x12e990086e4fd43d}}, - {{0xf10c96b37fdfbb2e, 0x9f9a935e121ceaf9, 0xdf1136c43a5b983f, 0x77b2e3f05d3e99af}}}, -{{{0xfd0d75879cf12657, 0xe82fef94e53a0e29, 0xcc34a7f05bbb4be7, 0x0b251172a50c38a2}}, - {{0x9532f48fcc5cd29b, 0x2ba851bea3ce3671, 0x32dacaa051122941, 0x478d99d9350004f2}}, - {{0x1d5ad94890bb02c0, 0x50e208b10ec25115, 0xa26a22894ef21702, 0x4dc923343b524805}}}, -{{{0xe3828c400f8086b6, 0x3f77e6f7979f0dc8, 0x7ef6de304df42cb4, 0x5265797cb6abd784}}, - {{0x3ad3e3ebf36c4975, 0xd75d25a537862125, 0xe873943da025a516, 0x6bbc7cb4c411c847}}, - {{0x3c6f9cd1d4a50d56, 0xb6244077c6feab7e, 0x6ff9bf483580972e, 0x00375883b332acfb}}}, -{{{0x0001b2cd28cb0940, 0x63fb51a06f1c24c9, 0xb5ad8691dcd5ca31, 0x67238dbd8c450660}}, - {{0xc98bec856c75c99c, 0xe44184c000e33cf4, 0x0a676b9bba907634, 0x669e2cb571f379d7}}, - {{0xcb116b73a49bd308, 0x025aad6b2392729e, 0xb4793efa3f55d9b1, 0x72a1056140678bb9}}}, -{{{0xa2b6812b1cc9249d, 0x62866eee21211f58, 0x2cb5c5b85df10ece, 0x03a6b259e263ae00}}, - {{0x0d8d2909e2e505b6, 0x98ca78abc0291230, 0x77ef5569a9b12327, 0x7c77897b81439b47}}, - {{0xf1c1b5e2de331cb5, 0x5a9f5d8e15fca420, 0x9fa438f17bd932b1, 0x2a381bf01c6146e7}}}, -{{{0xac9b9879cfc811c1, 0x8b7d29813756e567, 0x50da4e607c70edfc, 0x5dbca62f884400b6}}, - {{0xf7c0be32b534166f, 0x27e6ca6419cf70d4, 0x934df7d7a957a759, 0x5701461dabdec2aa}}, - {{0x2c6747402c915c25, 0x1bdcd1a80b0d340a, 0x5e5601bd07b43f5f, 0x2555b4e05539a242}}}, -{{{0x6fc09f5266ddd216, 0xdce560a7c8e37048, 0xec65939da2df62fd, 0x7a869ae7e52ed192}}, - {{0x78409b1d87e463d4, 0xad4da95acdfb639d, 0xec28773755259b9c, 0x69c806e9c31230ab}}, - {{0x7b48f57414bb3f22, 0x68c7cee4aedccc88, 0xed2f936179ed80be, 0x25d70b885f77bc4b}}}, -{{{0x4151c3d9762bf4de, 0x083f435f2745d82b, 0x29775a2e0d23ddd5, 0x138e3a6269a5db24}}, - {{0x98459d29bb1ae4d4, 0x56b9c4c739f954ec, 0x832743f6c29b4b3e, 0x21ea8e2798b6878a}}, - {{0x87bef4b46a5a7b9c, 0xd2299d1b5fc1d062, 0x82409818dd321648, 0x5c5abeb1e5a2e03d}}}, -{{{0x14722af4b73c2ddb, 0xbc470c5f5a05060d, 0x00943eac2581b02e, 0x0e434b3b1f499c8f}}, - {{0x02cde6de1306a233, 0x7b5a52a2116f8ec7, 0xe1c681f4c1163b5b, 0x241d350660d32643}}, - {{0x6be4404d0ebc52c7, 0xae46233bb1a791f5, 0x2aec170ed25db42b, 0x1d8dfd966645d694}}}, -{{{0x296fa9c59c2ec4de, 0xbc8b61bf4f84f3cb, 0x1c7706d917a8f908, 0x63b795fc7ad3255d}}, - {{0xd598639c12ddb0a4, 0xa5d19f30c024866b, 0xd17c2f0358fce460, 0x07a195152e095e8a}}, - {{0xa8368f02389e5fc8, 0x90433b02cf8de43b, 0xafa1fd5dc5412643, 0x3e8fe83d032f0137}}}, -{{{0x2f8b15b90570a294, 0x94f2427067084549, 0xde1c5ae161bbfd84, 0x75ba3b797fac4007}}, - {{0x08704c8de8efd13c, 0xdfc51a8e33e03731, 0xa59d5da51260cde3, 0x22d60899a6258c86}}, - {{0x6239dbc070cdd196, 0x60fe8a8b6c7d8a9a, 0xb38847bceb401260, 0x0904d07b87779e5e}}}, -{{{0xb4ce1fd4ddba919c, 0xcf31db3ec74c8daa, 0x2c63cc63ad86cc51, 0x43e2143fbc1dde07}}, - {{0xf4322d6648f940b9, 0x06952f0cbd2d0c39, 0x167697ada081f931, 0x6240aacebaf72a6c}}, - {{0xf834749c5ba295a0, 0xd6947c5bca37d25a, 0x66f13ba7e7c9316a, 0x56bdaf238db40cac}}}, -{{{0x362ab9e3f53533eb, 0x338568d56eb93d40, 0x9e0e14521d5a5572, 0x1d24a86d83741318}}, - {{0x1310d36cc19d3bb2, 0x062a6bb7622386b9, 0x7c9b8591d7a14f5c, 0x03aa31507e1e5754}}, - {{0xf4ec7648ffd4ce1f, 0xe045eaf054ac8c1c, 0x88d225821d09357c, 0x43b261dc9aeb4859}}}, -{{{0xe55b1e1988bb79bb, 0xa09ed07dc17a359d, 0xb02c2ee2603dea33, 0x326055cf5b276bc2}}, - {{0x19513d8b6c951364, 0x94fe7126000bf47b, 0x028d10ddd54f9567, 0x02b4d5e242940964}}, - {{0xb4a155cb28d18df2, 0xeacc4646186ce508, 0xc49cf4936c824389, 0x27a6c809ae5d3410}}}, -{{{0x8ba6ebcd1f0db188, 0x37d3d73a675a5be8, 0xf22edfa315f5585a, 0x2cb67174ff60a17e}}, - {{0xcd2c270ac43d6954, 0xdd4a3e576a66cab2, 0x79fa592469d7036c, 0x221503603d8c2599}}, - {{0x59eecdf9390be1d0, 0xa9422044728ce3f1, 0x82891c667a94f0f4, 0x7b1df4b73890f436}}}, -{{{0xe492f2e0b3b2a224, 0x7c6c9e062b551160, 0x15eb8fe20d7f7b0e, 0x61fcef2658fc5992}}, - {{0x5f2e221807f8f58c, 0xe3555c9fd49409d4, 0xb2aaa88d1fb6a630, 0x68698245d352e03d}}, - {{0xdbb15d852a18187a, 0xf3e4aad386ddacd7, 0x44bae2810ff6c482, 0x46cf4c473daf01cf}}}, -{{{0x426525ed9ec4e5f9, 0x0e5eda0116903303, 0x72b1a7f2cbe5cadc, 0x29387bcd14eb5f40}}, - {{0x213c6ea7f1498140, 0x7c1e7ef8392b4854, 0x2488c38c5629ceba, 0x1065aae50d8cc5bb}}, - {{0x1c2c4525df200d57, 0x5c3b2dd6bfca674a, 0x0a07e7b1e1834030, 0x69a198e64f1ce716}}}, -{{{0x7afcd613efa9d697, 0x0cc45aa41c067959, 0xa56fe104c1fada96, 0x3a73b70472e40365}}, - {{0x7b26e56b9e2d4734, 0xc4c7132b81c61675, 0xef5c9525ec9cde7f, 0x39c80b16e71743ad}}, - {{0x0f196e0d1b826c68, 0xf71ff0e24960e3db, 0x6113167023b7436c, 0x0cf0ea5877da7282}}}, -{{{0x196c80a4ddd4ccbd, 0x22e6f55d95f2dd9d, 0xc75e33c740d6c71b, 0x7bb51279cb3c042f}}, - {{0xe332ced43ba6945a, 0xde0b1361e881c05d, 0x1ad40f095e67ed3b, 0x5da8acdab8c63d5d}}, - {{0xc4b6664a3a70159f, 0x76194f0f0a904e14, 0xa5614c39a4096c13, 0x6cd0ff50979feced}}}, -{{{0xc0e067e78f4428ac, 0x14835ab0a61135e3, 0xf21d14f338062935, 0x6390a4c8df04849c}}, - {{0x7fecfabdb04ba18e, 0xd0fc7bfc3bddbcf7, 0xa41d486e057a131c, 0x641a4391f2223a61}}, - {{0xc5c6b95aa606a8db, 0x914b7f9eb06825f1, 0x2a731f6b44fc9eff, 0x30ddf38562705cfc}}}, -{{{0x4e3dcbdad1bff7f9, 0xc9118e8220645717, 0xbacccebc0f189d56, 0x1b4822e9d4467668}}, - {{0x33bef2bd68bcd52c, 0xc649dbb069482ef2, 0xb5b6ee0c41cb1aee, 0x5c294d270212a7e5}}, - {{0xab360a7f25563781, 0x2512228a480f7958, 0xc75d05276114b4e3, 0x222d9625d976fe2a}}}, -{{{0x1c717f85b372ace1, 0x81930e694638bf18, 0x239cad056bc08b58, 0x0b34271c87f8fff4}}, - {{0x0f94be7e0a344f85, 0xeb2faa8c87f22c38, 0x9ce1e75e4ee16f0f, 0x43e64e5418a08dea}}, - {{0x8155e2521a35ce63, 0xbe100d4df912028e, 0xbff80bf8a57ddcec, 0x57342dc96d6bc6e4}}}, -{{{0xefeef065c8ce5998, 0xbf029510b5cbeaa2, 0x8c64a10620b7c458, 0x35134fb231c24855}}, - {{0xf3c3bcb71e707bf6, 0x351d9b8c7291a762, 0x00502e6edad69a33, 0x522f521f1ec8807f}}, - {{0x272c1f46f9a3902b, 0xc91ba3b799657bcc, 0xae614b304f8a1c0e, 0x7afcaad70b99017b}}}, -{{{0xc25ded54a4b8be41, 0x902d13e11bb0e2dd, 0x41f43233cde82ab2, 0x1085faa5c3aae7cb}}, - {{0xa88141ecef842b6b, 0x55e7b14797abe6c5, 0x8c748f9703784ffe, 0x5b50a1f7afcd00b7}}, - {{0x9b840f66f1361315, 0x18462242701003e9, 0x65ed45fae4a25080, 0x0a2862393fda7320}}}, -{{{0x46ab13c8347cbc9d, 0x3849e8d499c12383, 0x4cea314087d64ac9, 0x1f354134b1a29ee7}}, - {{0x960e737b6ecb9d17, 0xfaf24948d67ceae1, 0x37e7a9b4d55e1b89, 0x5cb7173cb46c59eb}}, - {{0x4a89e68b82b7abf0, 0xf41cd9279ba6b7b9, 0x16e6c210e18d876f, 0x7cacdb0f7f1b09c6}}}, -{{{0x9062b2e0d91a78bc, 0x47c9889cc8509667, 0x9df54a66405070b8, 0x7369e6a92493a1bf}}, - {{0xe1014434dcc5caed, 0x47ed5d963c84fb33, 0x70019576ed86a0e7, 0x25b2697bd267f9e4}}, - {{0x9d673ffb13986864, 0x3ca5fbd9415dc7b8, 0xe04ecc3bdf273b5e, 0x1420683db54e4cd2}}}, -{{{0xb478bd1e249dd197, 0x620c35005e58c102, 0xfb02d32fccbaac5c, 0x60b63bebf508a72d}}, - {{0x34eebb6fc1cc5ad0, 0x6a1b0ce99646ac8b, 0xd3b0da49a66bde53, 0x31e83b4161d081c1}}, - {{0x97e8c7129e062b4f, 0x49e48f4f29320ad8, 0x5bece14b6f18683f, 0x55cf1eb62d550317}}}, -{{{0x5879101065c23d58, 0x8b9d086d5094819c, 0xe2402fa912c55fa7, 0x669a6564570891d4}}, - {{0x3076b5e37df58c52, 0xd73ab9dde799cc36, 0xbd831ce34913ee20, 0x1a56fbaa62ba0133}}, - {{0x943e6b505c9dc9ec, 0x302557bba77c371a, 0x9873ae5641347651, 0x13c4836799c58a5c}}}, -{{{0x423a5d465ab3e1b9, 0xfc13c187c7f13f61, 0x19f83664ecb5b9b6, 0x66f80c93a637b607}}, - {{0xc4dcfb6a5d8bd080, 0xdeebc4ec571a4842, 0xd4b2e883b8e55365, 0x50bdc87dc8e5b827}}, - {{0x606d37836edfe111, 0x32353e15f011abd9, 0x64b03ac325b73b96, 0x1dd56444725fd5ae}}}, -{{{0x8fa47ff83362127d, 0xbc9f6ac471cd7c15, 0x6e71454349220c8b, 0x0e645912219f732e}}, - {{0xc297e60008bac89a, 0x7d4cea11eae1c3e0, 0xf3e38be19fe7977c, 0x3a3a450f63a305cd}}, - {{0x078f2f31d8394627, 0x389d3183de94a510, 0xd1e36c6d17996f80, 0x318c8d9393a9a87b}}}, -{{{0xf2745d032afffe19, 0x0c9f3c497f24db66, 0xbc98d3e3ba8598ef, 0x224c7c679a1d5314}}, - {{0x5d669e29ab1dd398, 0xfc921658342d9e3b, 0x55851dfdf35973cd, 0x509a41c325950af6}}, - {{0xbdc06edca6f925e9, 0x793ef3f4641b1f33, 0x82ec12809d833e89, 0x05bff02328a11389}}}, -{{{0x3632137023cae00b, 0x544acf0ad1accf59, 0x96741049d21a1c88, 0x780b8cc3fa2a44a7}}, - {{0x6881a0dd0dc512e4, 0x4fe70dc844a5fafe, 0x1f748e6b8f4a5240, 0x576277cdee01a3ea}}, - {{0x1ef38abc234f305f, 0x9a577fbd1405de08, 0x5e82a51434e62a0d, 0x5ff418726271b7a1}}}, -{{{0x398e080c1789db9d, 0xa7602025f3e778f5, 0xfa98894c06bd035d, 0x106a03dc25a966be}}, - {{0xe5db47e813b69540, 0xf35d2a3b432610e1, 0xac1f26e938781276, 0x29d4db8ca0a0cb69}}, - {{0xd9ad0aaf333353d0, 0x38669da5acd309e5, 0x3c57658ac888f7f0, 0x4ab38a51052cbefa}}}, -{{{0xdfdacbee4324c0e9, 0x054442883f955bb7, 0xdef7aaa8ea31609f, 0x68aee70642287cff}}, - {{0xf68fe2e8809de054, 0xe3bc096a9c82bad1, 0x076353d40aadbf45, 0x7b9b1fb5dea1959e}}, - {{0xf01cc8f17471cc0c, 0x95242e37579082bb, 0x27776093d3e46b5f, 0x2d13d55a28bd85fb}}}, -{{{0xfac5d2065b35b8da, 0xa8da8a9a85624bb7, 0xccd2ca913d21cd0f, 0x6b8341ee8bf90d58}}, - {{0xbf019cce7aee7a52, 0xa8ded2b6e454ead3, 0x3c619f0b87a8bb19, 0x3619b5d7560916d8}}, - {{0x3579f26b0282c4b2, 0x64d592f24fafefae, 0xb7cded7b28c8c7c0, 0x6a927b6b7173a8d7}}}, -{{{0x1f6db24f986e4656, 0x1021c02ed1e9105b, 0xf8ff3fff2cc0a375, 0x1d2a6bf8c6c82592}}, - {{0x8d7040863ece88eb, 0xf0e307a980eec08c, 0xac2250610d788fda, 0x056d92a43a0d478d}}, - {{0x1b05a196fc3da5a1, 0x77d7a8c243b59ed0, 0x06da3d6297d17918, 0x66fbb494f12353f7}}}, -{{{0x751a50b9d85c0fb8, 0xd1afdc258bcf097b, 0x2f16a6a38309a969, 0x14ddff9ee5b00659}}, - {{0xd6d70996f12309d6, 0xdbfb2385e9c3d539, 0x46d602b0f7552411, 0x270a0b0557843e0c}}, - {{0x61ff0640a7862bcc, 0x81cac09a5f11abfe, 0x9047830455d12abb, 0x19a4bde1945ae873}}}, -{{{0x9b9f26f520a6200a, 0x64804443cf13eaf8, 0x8a63673f8631edd3, 0x72bbbce11ed39dc1}}, - {{0x40c709dec076c49f, 0x657bfaf27f3e53f6, 0x40662331eca042c4, 0x14b375487eb4df04}}, - {{0xae853c94ab66dc47, 0xeb62343edf762d6e, 0xf08e0e186fb2f7d1, 0x4f0b1c02700ab37a}}}, -{{{0xe1706787d81951fa, 0xa10a2c8eb290c77b, 0xe7382fa03ed66773, 0x0a4d84710bcc4b54}}, - {{0x79fd21ccc1b2e23f, 0x4ae7c281453df52a, 0xc8172ec9d151486b, 0x68abe9443e0a7534}}, - {{0xda12c6c407831dcb, 0x0da230d74d5c510d, 0x4ab1531e6bd404e1, 0x4106b166bcf440ef}}}, -{{{0x02e57a421cd23668, 0x4ad9fb5d0eaef6fd, 0x954e6727b1244480, 0x7f792f9d2699f331}}, - {{0xa485ccd539e4ecf2, 0x5aa3f3ad0555bab5, 0x145e3439937df82d, 0x1238b51e1214283f}}, - {{0x0b886b925fd4d924, 0x60906f7a3626a80d, 0xecd367b4b98abd12, 0x2876beb1def344cf}}}, -{{{0xdc84e93563144691, 0x632fe8a0d61f23f4, 0x4caa800612a9a8d5, 0x48f9dbfa0e9918d3}}, - {{0xd594b3333a8a85f8, 0x4ea37689e78d7d58, 0x73bf9f455e8e351f, 0x5507d7d2bc41ebb4}}, - {{0x1ceb2903299572fc, 0x7c8ccaa29502d0ee, 0x91bfa43411cce67b, 0x5784481964a831e7}}}, -{{{0xda7c2b256768d593, 0x98c1c0574422ca13, 0xf1a80bd5ca0ace1d, 0x29cdd1adc088a690}}, - {{0xd6cfd1ef5fddc09c, 0xe82b3efdf7575dce, 0x25d56b5d201634c2, 0x3041c6bb04ed2b9b}}, - {{0x0ff2f2f9d956e148, 0xade797759f356b2e, 0x1a4698bb5f6c025c, 0x104bbd6814049a7b}}}, -{{{0x51f0fd3168f1ed67, 0x2c811dcdd86f3bc2, 0x44dc5c4304d2f2de, 0x5be8cc57092a7149}}, - {{0xa95d9a5fd67ff163, 0xe92be69d4cc75681, 0xb7f8024cde20f257, 0x204f2a20fb072df5}}, - {{0xc8143b3d30ebb079, 0x7589155abd652e30, 0x653c3c318f6d5c31, 0x2570fb17c279161f}}}, -{{{0x3efa367f2cb61575, 0xf5f96f761cd6026c, 0xe8c7142a65b52562, 0x3dcb65ea53030acd}}, - {{0x192ea9550bb8245a, 0xc8e6fba88f9050d1, 0x7986ea2d88a4c935, 0x241c5f91de018668}}, - {{0x28d8172940de6caa, 0x8fbf2cf022d9733a, 0x16d7fcdd235b01d1, 0x08420edd5fcdf0e5}}}, -{{{0xcdff20ab8362fa4a, 0x57e118d4e21a3e6e, 0xe3179617fc39e62b, 0x0d9a53efbc1769fd}}, - {{0x0358c34e04f410ce, 0xb6135b5a276e0685, 0x5d9670c7ebb91521, 0x04d654f321db889c}}, - {{0x5e7dc116ddbdb5d5, 0x2954deb68da5dd2d, 0x1cb608173334a292, 0x4a7a4f2618991ad7}}}, -{{{0xf4a718025fb15f95, 0x3df65f346b5c1b8f, 0xcdfcf08500e01112, 0x11b50c4cddd31848}}, - {{0x24c3b291af372a4b, 0x93da8270718147f2, 0xdd84856486899ef2, 0x4a96314223e0ee33}}, - {{0xa6e8274408a4ffd6, 0x738e177e9c1576d9, 0x773348b63d02b3f2, 0x4f4bce4dce6bcc51}}}, -{{{0xa71fce5ae2242584, 0x26ea725692f58a9e, 0xd21a09d71cea3cf4, 0x73fcdd14b71c01e6}}, - {{0x30e2616ec49d0b6f, 0xe456718fcaec2317, 0x48eb409bf26b4fa6, 0x3042cee561595f37}}, - {{0x427e7079449bac41, 0x855ae36dbce2310a, 0x4cae76215f841a7c, 0x389e740c9a9ce1d6}}}, -{{{0x64fcb3ae34dcb9ce, 0x97500323e348d0ad, 0x45b3f07d62c6381b, 0x61545379465a6788}}, - {{0xc9bd78f6570eac28, 0xe55b0b3227919ce1, 0x65fc3eaba19b91ed, 0x25c425e5d6263690}}, - {{0x3f3e06a6f1d7de6e, 0x3ef976278e062308, 0x8c14f6264e8a6c77, 0x6539a08915484759}}}, -{{{0xe9d21f74c3d2f773, 0xc150544125c46845, 0x624e5ce8f9b99e33, 0x11c5e4aac5cd186c}}, - {{0xddc4dbd414bb4a19, 0x19b2bc3c98424f8e, 0x48a89fd736ca7169, 0x0f65320ef019bd90}}, - {{0xd486d1b1cafde0c6, 0x4f3fe6e3163b5181, 0x59a8af0dfaf2939a, 0x4cabc7bdec33072a}}}, -{{{0x16faa8fb532f7428, 0xdbd42ea046a4e272, 0x5337653b8b9ea480, 0x4065947223973f03}}, - {{0xf7c0a19c1a54a044, 0x4a1c5e2477bd9fbb, 0xa6e3ca115af22972, 0x1819bb953f2e9e0d}}, - {{0x498fbb795e042e84, 0x7d0dd89a7698b714, 0x8bfb0ba427fe6295, 0x36ba82e721200524}}}, -{{{0xd60ecbb74245ec41, 0xfd9be89e34348716, 0xc9240afee42284de, 0x4472f648d0531db4}}, - {{0xc8d69d0a57274ed5, 0x45ba803260804b17, 0xdf3cda102255dfac, 0x77d221232709b339}}, - {{0x498a6d7064ad94d8, 0xa5b5c8fd9af62263, 0x8ca8ed0545c141f4, 0x2c63bec3662d358c}}}, -{{{0x7fe60d8bea787955, 0xb9dc117eb5f401b7, 0x91c7c09a19355cce, 0x22692ef59442bedf}}, - {{0x9a518b3a8586f8bf, 0x9ee71af6cbb196f0, 0xaa0625e6a2385cf2, 0x1deb2176ddd7c8d1}}, - {{0x8563d19a2066cf6c, 0x401bfd8c4dcc7cd7, 0xd976a6becd0d8f62, 0x67cfd773a278b05e}}}, -{{{0x8dec31faef3ee475, 0x99dbff8a9e22fd92, 0x512d11594e26cab1, 0x0cde561eec4310b9}}, - {{0x2d5fa9855a4e586a, 0x65f8f7a449beab7e, 0xaa074dddf21d33d3, 0x185cba721bcb9dee}}, - {{0x93869da3f4e3cb41, 0xbf0392f540f7977e, 0x026204fcd0463b83, 0x3ec91a769eec6eed}}}, -{{{0x1e9df75bf78166ad, 0x4dfda838eb0cd7af, 0xba002ed8c1eaf988, 0x13fedb3e11f33cfc}}, - {{0x0fad2fb7b0a3402f, 0x46615ecbfb69f4a8, 0xf745bcc8c5f8eaa6, 0x7a5fa8794a94e896}}, - {{0x52958faa13cd67a1, 0x965ee0818bdbb517, 0x16e58daa2e8845b3, 0x357d397d5499da8f}}}, -{{{0x1ebfa05fb0bace6c, 0xc934620c1caf9a1e, 0xcc771cc41d82b61a, 0x2d94a16aa5f74fec}}, - {{0x481dacb4194bfbf8, 0x4d77e3f1bae58299, 0x1ef4612e7d1372a0, 0x3a8d867e70ff69e1}}, - {{0x6f58cd5d55aff958, 0xba3eaa5c75567721, 0x75c123999165227d, 0x69be1343c2f2b35e}}}, -{{{0x0e091d5ee197c92a, 0x4f51019f2945119f, 0x143679b9f034e99c, 0x7d88112e4d24c696}}, - {{0x82bbbdac684b8de3, 0xa2f4c7d03fca0718, 0x337f92fbe096aaa8, 0x200d4d8c63587376}}, - {{0x208aed4b4893b32b, 0x3efbf23ebe59b964, 0xd762deb0dba5e507, 0x69607bd681bd9d94}}}, -{{{0xf6be021068de1ce1, 0xe8d518e70edcbc1f, 0xe3effdd01b5505a5, 0x35f63353d3ec3fd0}}, - {{0x3b7f3bd49323a902, 0x7c21b5566b2c6e53, 0xe5ba8ff53a7852a7, 0x28bc77a5838ece00}}, - {{0x63ba78a8e25d8036, 0x63651e0094333490, 0x48d82f20288ce532, 0x3a31abfa36b57524}}}, -{{{0x239e9624089c0a2e, 0xc748c4c03afe4738, 0x17dbed2a764fa12a, 0x639b93f0321c8582}}, - {{0xc08f788f3f78d289, 0xfe30a72ca1404d9f, 0xf2778bfccf65cc9d, 0x7ee498165acb2021}}, - {{0x7bd508e39111a1c3, 0x2b2b90d480907489, 0xe7d2aec2ae72fd19, 0x0edf493c85b602a6}}}, -{{{0xaecc8158599b5a68, 0xea574f0febade20e, 0x4fe41d7422b67f07, 0x403b92e3019d4fb4}}, - {{0x6767c4d284764113, 0xa090403ff7f5f835, 0x1c8fcffacae6bede, 0x04c00c54d1dfa369}}, - {{0x4dc22f818b465cf8, 0x71a0f35a1480eff8, 0xaee8bfad04c7d657, 0x355bb12ab26176f4}}}, -{{{0xa71e64cc7493bbf4, 0xe5bd84d9eca3b0c3, 0x0a6bc50cfa05e785, 0x0f9b8132182ec312}}, - {{0xa301dac75a8c7318, 0xed90039db3ceaa11, 0x6f077cbf3bae3f2d, 0x7518eaf8e052ad8e}}, - {{0xa48859c41b7f6c32, 0x0f2d60bcf4383298, 0x1815a929c9b1d1d9, 0x47c3871bbb1755c4}}}, -{{{0x5144539771ec4f48, 0xf805b17dc98c5d6e, 0xf762c11a47c3c66b, 0x00b89b85764699dc}}, - {{0xfbe65d50c85066b0, 0x62ecc4b0b3a299b0, 0xe53754ea441ae8e0, 0x08fea02ce8d48d5f}}, - {{0x824ddd7668deead0, 0xc86445204b685d23, 0xb514cfcd5d89d665, 0x473829a74f75d537}}}, -{{{0x82d2da754679c418, 0xe63bd7d8b2618df0, 0x355eef24ac47eb0a, 0x2078684c4833c6b4}}, - {{0x23d9533aad3902c9, 0x64c2ddceef03588f, 0x15257390cfe12fb4, 0x6c668b4d44e4d390}}, - {{0x3b48cf217a78820c, 0xf76a0ab281273e97, 0xa96c65a78c8eed7b, 0x7411a6054f8a433f}}}, -{{{0x4d659d32b99dc86d, 0x044cdc75603af115, 0xb34c712cdcc2e488, 0x7c136574fb8134ff}}, - {{0x579ae53d18b175b4, 0x68713159f392a102, 0x8455ecba1eef35f5, 0x1ec9a872458c398f}}, - {{0xb8e6a4d400a2509b, 0x9b81d7020bc882b4, 0x57e7cc9bf1957561, 0x3add88a5c7cd6460}}}, -{{{0xab895770b635dcf2, 0x02dfef6cf66c1fbc, 0x85530268beb6d187, 0x249929fccc879e74}}, - {{0x85c298d459393046, 0x8f7e35985ff659ec, 0x1d2ca22af2f66e3a, 0x61ba1131a406a720}}, - {{0xa3d0a0f116959029, 0x023b6b6cba7ebd89, 0x7bf15a3e26783307, 0x5620310cbbd8ece7}}}, -{{{0x528993434934d643, 0xb9dbf806a51222f5, 0x8f6d878fc3f41c22, 0x37676a2a4d9d9730}}, - {{0x6646b5f477e285d6, 0x40e8ff676c8f6193, 0xa6ec7311abb594dd, 0x7ec846f3658cec4d}}, - {{0x9b5e8f3f1da22ec7, 0x130f1d776c01cd13, 0x214c8fcfa2989fb8, 0x6daaf723399b9dd5}}}, -{{{0x591e4a5610628564, 0x2a4bb87ca8b4df34, 0xde2a2572e7a38e43, 0x3cbdabd9fee5046e}}, - {{0x81aebbdd2cd13070, 0x962e4325f85a0e9e, 0xde9391aacadffecb, 0x53177fda52c230e6}}, - {{0xa7bc970650b9de79, 0x3d12a7fbc301b59b, 0x02652e68d36ae38c, 0x79d739835a6199dc}}}, -{{{0xd9354df64131c1bd, 0x758094a186ec5822, 0x4464ee12e459f3c2, 0x6c11fce4cb133282}}, - {{0x21c9d9920d591737, 0x9bea41d2e9b46cd6, 0xe20e84200d89bfca, 0x79d99f946eae5ff8}}, - {{0xf17b483568673205, 0x387deae83caad96c, 0x61b471fd56ffe386, 0x31741195b745a599}}}, -{{{0xe8d10190b77a360b, 0x99b983209995e702, 0xbd4fdff8fa0247aa, 0x2772e344e0d36a87}}, - {{0x17f8ba683b02a047, 0x50212096feefb6c8, 0x70139be21556cbe2, 0x203e44a11d98915b}}, - {{0xd6863eba37b9e39f, 0x105bc169723b5a23, 0x104f6459a65c0762, 0x567951295b4d38d4}}}, -{{{0x535fd60613037524, 0xe210adf6b0fbc26a, 0xac8d0a9b23e990ae, 0x47204d08d72fdbf9}}, - {{0x07242eb30d4b497f, 0x1ef96306b9bccc87, 0x37950934d8116f45, 0x05468d6201405b04}}, - {{0x00f565a9f93267de, 0xcecfd78dc0d58e8a, 0xa215e2dcf318e28e, 0x4599ee919b633352}}}, -{{{0xd3c220ca70e0e76b, 0xb12bea58ea9f3094, 0x294ddec8c3271282, 0x0c3539e1a1d1d028}}, - {{0xac746d6b861ae579, 0x31ab0650f6aea9dc, 0x241d661140256d4c, 0x2f485e853d21a5de}}, - {{0x329744839c0833f3, 0x6fe6257fd2abc484, 0x5327d1814b358817, 0x65712585893fe9bc}}}, -{{{0x9c102fb732a61161, 0xe48e10dd34d520a8, 0x365c63546f9a9176, 0x32f6fe4c046f6006}}, - {{0x81c29f1bd708ee3f, 0xddcb5a05ae6407d0, 0x97aec1d7d2a3eba7, 0x1590521a91d50831}}, - {{0x40a3a11ec7910acc, 0x9013dff8f16d27ae, 0x1a9720d8abb195d4, 0x1bb9fe452ea98463}}}, -{{{0xe9d1d950b3d54f9e, 0x2d5f9cbee00d33c1, 0x51c2c656a04fc6ac, 0x65c091ee3c1cbcc9}}, - {{0xcf5e6c95cc36747c, 0x294201536b0bc30d, 0x453ac67cee797af0, 0x5eae6ab32a8bb3c9}}, - {{0x7083661114f118ea, 0x2b37b87b94349cad, 0x7273f51cb4e99f40, 0x78a2a95823d75698}}}, -{{{0xa2b072e95c8c2ace, 0x69cffc96651e9c4b, 0x44328ef842e7b42b, 0x5dd996c122aadeb3}}, - {{0xb4f23c425ef83207, 0xabf894d3c9a934b5, 0xd0708c1339fd87f7, 0x1876789117166130}}, - {{0x925b5ef0670c507c, 0x819bc842b93c33bf, 0x10792e9a70dd003f, 0x59ad4b7a6e28dc74}}}, -{{{0x5f3a7562eb3dbe47, 0xf7ea38548ebda0b8, 0x00c3e53145747299, 0x1304e9e71627d551}}, - {{0x583b04bfacad8ea2, 0x29b743e8148be884, 0x2b1e583b0810c5db, 0x2b5449e58eb3bbaa}}, - {{0x789814d26adc9cfe, 0x3c1bab3f8b48dd0b, 0xda0fe1fff979c60a, 0x4468de2d7c2dd693}}}, -{{{0x51bb355e9419469e, 0x33e6dc4c23ddc754, 0x93a5b6d6447f9962, 0x6cce7c6ffb44bd63}}, - {{0x4b9ad8c6f86307ce, 0x21113531435d0c28, 0xd4a866c5657a772c, 0x5da6427e63247352}}, - {{0x1a94c688deac22ca, 0xb9066ef7bbae1ff8, 0x88ad8c388d59580f, 0x58f29abfe79f2ca8}}}, -{{{0xe90ecfab8de73e68, 0x54036f9f377e76a5, 0xf0495b0bbe015982, 0x577629c4a7f41e36}}, - {{0x4b5a64bf710ecdf6, 0xb14ce538462c293c, 0x3643d056d50b3ab9, 0x6af93724185b4870}}, - {{0x3220024509c6a888, 0xd2e036134b558973, 0x83e236233c33289f, 0x701f25bb0caec18f}}}, -{{{0xc3a8b0f8e4616ced, 0xf700660e9e25a87d, 0x61e3061ff4bca59c, 0x2e0c92bfbdc40be9}}, - {{0x9d18f6d97cbec113, 0x844a06e674bfdbe4, 0x20f5b522ac4e60d6, 0x720a5bc050955e51}}, - {{0x0c3f09439b805a35, 0xe84e8b376242abfc, 0x691417f35c229346, 0x0e9b9cbb144ef0ec}}}, -{{{0xfbbad48ffb5720ad, 0xee81916bdbf90d0e, 0xd4813152635543bf, 0x221104eb3f337bd8}}, - {{0x8dee9bd55db1beee, 0xc9c3ab370a723fb9, 0x44a8f1bf1c68d791, 0x366d44191cfd3cde}}, - {{0x9e3c1743f2bc8c14, 0x2eda26fcb5856c3b, 0xccb82f0e68a7fb97, 0x4167a4e6bc593244}}}, -{{{0x643b9d2876f62700, 0x5d1d9d400e7668eb, 0x1b4b430321fc0684, 0x7938bb7e2255246a}}, - {{0xc2be2665f8ce8fee, 0xe967ff14e880d62c, 0xf12e6e7e2f364eee, 0x34b33370cb7ed2f6}}, - {{0xcdc591ee8681d6cc, 0xce02109ced85a753, 0xed7485c158808883, 0x1176fc6e2dfe65e4}}}, -{{{0xb4af6cd05b9c619b, 0x2ddfc9f4b2a58480, 0x3d4fa502ebe94dc4, 0x08fc3a4c677d5f34}}, - {{0xdb90e28949770eb8, 0x98fbcc2aacf440a3, 0x21354ffeded7879b, 0x1f6a3e54f26906b6}}, - {{0x60a4c199d30734ea, 0x40c085b631165cd6, 0xe2333e23f7598295, 0x4f2fad0116b900d1}}}, -{{{0x44beb24194ae4e54, 0x5f541c511857ef6c, 0xa61e6b2d368d0498, 0x445484a4972ef7ab}}, - {{0x962cd91db73bb638, 0xe60577aafc129c08, 0x6f619b39f3b61689, 0x3451995f2944ee81}}, - {{0x9152fcd09fea7d7c, 0x4a816c94b0935cf6, 0x258e9aaa47285c40, 0x10b89ca6042893b7}}}, -{{{0x9b2a426e3b646025, 0x32127190385ce4cf, 0xa25cffc2dd6dea45, 0x06409010bea8de75}}, - {{0xd67cded679d34aa0, 0xcc0b9ec0cc4db39f, 0xa535a456e35d190f, 0x2e05d9eaf61f6fef}}, - {{0xc447901ad61beb59, 0x661f19bce5dc880a, 0x24685482b7ca6827, 0x293c778cefe07f26}}}, -{{{0x86809e7007069096, 0xaad75b15e4e50189, 0x07f35715a21a0147, 0x0487f3f112815d5e}}, - {{0x16c795d6a11ff200, 0xcb70d0e2b15815c9, 0x89f293209b5395b5, 0x50b8c2d031e47b4f}}, - {{0x48350c08068a4962, 0x6ffdd05351092c9a, 0x17af4f4aaf6fc8dd, 0x4b0553b53cdba58b}}}, -{{{0x9c65fcbe1b32ff79, 0xeb75ea9f03b50f9b, 0xfced2a6c6c07e606, 0x35106cd551717908}}, - {{0xbf05211b27c152d4, 0x5ec26849bd1af639, 0x5e0b2caa8e6fab98, 0x054c8bdd50bd0840}}, - {{0x38a0b12f1dcf073d, 0x4b60a8a3b7f6a276, 0xfed5ac25d3404f9a, 0x72e82d5e5505c229}}}, -{{{0x6b0b697ff0d844c8, 0xbb12f85cd979cb49, 0xd2a541c6c1da0f1f, 0x7b7c242958ce7211}}, - {{0x00d9cdfd69771d02, 0x410276cd6cfbf17e, 0x4c45306c1cb12ec7, 0x2857bf1627500861}}, - {{0x9f21903f0101689e, 0xd779dfd3bf861005, 0xa122ee5f3deb0f1b, 0x510df84b485a00d4}}}, -{{{0xa54133bb9277a1fa, 0x74ec3b6263991237, 0x1a3c54dc35d2f15a, 0x2d347144e482ba3a}}, - {{0x24b3c887c70ac15e, 0xb0f3a557fb81b732, 0x9b2cde2fe578cc1b, 0x4cf7ed0703b54f8e}}, - {{0x6bd47c6598fbee0f, 0x9e4733e2ab55be2d, 0x1093f624127610c5, 0x4e05e26ad0a1eaa4}}}, -{{{0xda9b6b624b531f20, 0x429a760e77509abb, 0xdbe9f522e823cb80, 0x618f1856880c8f82}}, - {{0x1833c773e18fe6c0, 0xe3c4711ad3c87265, 0x3bfd3c4f0116b283, 0x1955875eb4cd4db8}}, - {{0x6da6de8f0e399799, 0x7ad61aa440fda178, 0xb32cd8105e3563dd, 0x15f6beae2ae340ae}}}, -{{{0x862bcb0c31ec3a62, 0x810e2b451138f3c2, 0x788ec4b839dac2a4, 0x28f76867ae2a9281}}, - {{0xba9a0f7b9245e215, 0xf368612dd98c0dbb, 0x2e84e4cbf220b020, 0x6ba92fe962d90eda}}, - {{0x3e4df9655884e2aa, 0xbd62fbdbdbd465a5, 0xd7596caa0de9e524, 0x6e8042ccb2b1b3d7}}}, -{{{0xf10d3c29ce28ca6e, 0xbad34540fcb6093d, 0xe7426ed7a2ea2d3f, 0x08af9d4e4ff298b9}}, - {{0x1530653616521f7e, 0x660d06b896203dba, 0x2d3989bc545f0879, 0x4b5303af78ebd7b0}}, - {{0x72f8a6c3bebcbde8, 0x4f0fca4adc3a8e89, 0x6fa9d4e8c7bfdf7a, 0x0dcf2d679b624eb7}}}, -{{{0x3d5947499718289c, 0x12ebf8c524533f26, 0x0262bfcb14c3ef15, 0x20b878d577b7518e}}, - {{0x753941be5a45f06e, 0xd07caeed6d9c5f65, 0x11776b9c72ff51b6, 0x17d2d1d9ef0d4da9}}, - {{0x27f2af18073f3e6a, 0xfd3fe519d7521069, 0x22e3b72c3ca60022, 0x72214f63cc65c6a7}}}, -{{{0xb4e37f405307a693, 0xaba714d72f336795, 0xd6fbd0a773761099, 0x5fdf48c58171cbc9}}, - {{0x1d9db7b9f43b29c9, 0xd605824a4f518f75, 0xf2c072bd312f9dc4, 0x1f24ac855a1545b0}}, - {{0x24d608328e9505aa, 0x4748c1d10c1420ee, 0xc7ffe45c06fb25a2, 0x00ba739e2ae395e6}}}, -{{{0x592e98de5c8790d6, 0xe5bfb7d345c2a2df, 0x115a3b60f9b49922, 0x03283a3e67ad78f3}}, - {{0xae4426f5ea88bb26, 0x360679d984973bfb, 0x5c9f030c26694e50, 0x72297de7d518d226}}, - {{0x48241dc7be0cb939, 0x32f19b4d8b633080, 0xd3dfc90d02289308, 0x05e1296846271945}}}, -{{{0xba82eeb32d9c495a, 0xceefc8fcf12bb97c, 0xb02dabae93b5d1e0, 0x39c00c9c13698d9b}}, - {{0xadbfbbc8242c4550, 0xbcc80cecd03081d9, 0x843566a6f5c8df92, 0x78cf25d38258ce4c}}, - {{0x15ae6b8e31489d68, 0xaa851cab9c2bf087, 0xc9a75a97f04efa05, 0x006b52076b3ff832}}}, -{{{0x29e0cfe19d95781c, 0xb681df18966310e2, 0x57df39d370516b39, 0x4d57e3443bc76122}}, - {{0xf5cb7e16b9ce082d, 0x3407f14c417abc29, 0xd4b36bce2bf4a7ab, 0x7de2e9561a9f75ce}}, - {{0xde70d4f4b6a55ecb, 0x4801527f5d85db99, 0xdbc9c440d3ee9a81, 0x6b2a90af1a6029ed}}}, -{{{0x6923f4fc9ae61e97, 0x5735281de03f5fd1, 0xa764ae43e6edd12d, 0x5fd8f4e9d12d3e4a}}, - {{0x77ebf3245bb2d80a, 0xd8301b472fb9079b, 0xc647e6f24cee7333, 0x465812c8276c2109}}, - {{0x4d43beb22a1062d9, 0x7065fb753831dc16, 0x180d4a7bde2968d7, 0x05b32c2b1cb16790}}}, -{{{0xc8c05eccd24da8fd, 0xa1cf1aac05dfef83, 0xdbbeeff27df9cd61, 0x3b5556a37b471e99}}, - {{0xf7fca42c7ad58195, 0x3214286e4333f3cc, 0xb6c29d0d340b979d, 0x31771a48567307e1}}, - {{0x32b0c524e14dd482, 0xedb351541a2ba4b6, 0xa3d16048282b5af3, 0x4fc079d27a7336eb}}}, -{{{0x51c938b089bf2f7f, 0x2497bd6502dfe9a7, 0xffffc09c7880e453, 0x124567cecaf98e92}}, - {{0xdc348b440c86c50d, 0x1337cbc9cc94e651, 0x6422f74d643e3cb9, 0x241170c2bae3cd08}}, - {{0x3ff9ab860ac473b4, 0xf0911dee0113e435, 0x4ae75060ebc6c4af, 0x3f8612966c87000d}}}, -{{{0x0c9c5303f7957be4, 0xa3c31a20e085c145, 0xb0721d71d0850050, 0x0aba390eab0bf2da}}, - {{0x529fdffe638c7bf3, 0xdf2b9e60388b4995, 0xe027b34f1bad0249, 0x7bc92fc9b9fa74ed}}, - {{0x9f97ef2e801ad9f9, 0x83697d5479afda3a, 0xe906b3ffbd596b50, 0x02672b37dd3fb8e0}}}, -{{{0x48b2ca8b260885e4, 0xa4286bec82b34c1c, 0x937e1a2617f58f74, 0x741d1fcbab2ca2a5}}, - {{0xee9ba729398ca7f5, 0xeb9ca6257a4849db, 0x29eb29ce7ec544e1, 0x232ca21ef736e2c8}}, - {{0xbf61423d253fcb17, 0x08803ceafa39eb14, 0xf18602df9851c7af, 0x0400f3a049e3414b}}}, -{{{0xabce0476ba61c55b, 0x36a3d6d7c4d39716, 0x6eb259d5e8d82d09, 0x0c9176e984d756fb}}, - {{0x2efba412a06e7b06, 0x146785452c8d2560, 0xdf9713ebd67a91c7, 0x32830ac7157eadf3}}, - {{0x0e782a7ab73769e8, 0x04a05d7875b18e2c, 0x29525226ebcceae1, 0x0d794f8383eba820}}}, -{{{0xff35f5cb9e1516f4, 0xee805bcf648aae45, 0xf0d73c2bb93a9ef3, 0x097b0bf22092a6c2}}, - {{0x7be44ce7a7a2e1ac, 0x411fd93efad1b8b7, 0x1734a1d70d5f7c9b, 0x0d6592233127db16}}, - {{0xc48bab1521a9d733, 0xa6c2eaead61abb25, 0x625c6c1cc6cb4305, 0x7fc90fea93eb3a67}}}, -{{{0x0408f1fe1f5c5926, 0x1a8f2f5e3b258bf4, 0x40a951a2fdc71669, 0x6598ee93c98b577e}}, - {{0xc527deb59c7cb23d, 0x955391695328404e, 0xd64392817ccf2c7a, 0x6ce97dabf7d8fa11}}, - {{0x25b5a8e50ef7c48f, 0xeb6034116f2ce532, 0xc5e75173e53de537, 0x73119fa08c12bb03}}}, -{{{0xed30129453f1a4cb, 0xbce621c9c8f53787, 0xfacb2b1338bee7b9, 0x3025798a9ea8428c}}, - {{0x7845b94d21f4774d, 0xbf62f16c7897b727, 0x671857c03c56522b, 0x3cd6a85295621212}}, - {{0x3fecde923aeca999, 0xbdaa5b0062e8c12f, 0x67b99dfc96988ade, 0x3f52c02852661036}}}, -{{{0xffeaa48e2a1351c6, 0x28624754fa7f53d7, 0x0b5ba9e57582ddf1, 0x60c0104ba696ac59}}, - {{0x9258bf99eec416c6, 0xac8a5017a9d2f671, 0x629549ab16dea4ab, 0x05d0e85c99091569}}, - {{0x051de020de9cbe97, 0xfa07fc56b50bcf74, 0x378cec9f0f11df65, 0x36853c69ab96de4d}}}, -{{{0x36d9b8de78f39b2d, 0x7f42ed71a847b9ec, 0x241cd1d679bd3fde, 0x6a704fec92fbce6b}}, - {{0x4433c0b0fac5e7be, 0x724bae854c08dcbe, 0xf1f24cc446978f9b, 0x4a0aff6d62825fc8}}, - {{0xe917fb9e61095301, 0xc102df9402a092f8, 0xbf09e2f5fa66190b, 0x681109bee0dcfe37}}}, -{{{0x559a0cc9782a0dde, 0x551dcdb2ea718385, 0x7f62865b31ef238c, 0x504aa7767973613d}}, - {{0x9c18fcfa36048d13, 0x29159db373899ddd, 0xdc9f350b9f92d0aa, 0x26f57eee878a19d4}}, - {{0x0cab2cd55687efb1, 0x5180d162247af17b, 0x85c15a344f5a2467, 0x4041943d9dba3069}}}, -{{{0xc3c0eeba43ebcc96, 0x8d749c9c26ea9caf, 0xd9fa95ee1c77ccc6, 0x1420a1d97684340f}}, - {{0x4b217743a26caadd, 0x47a6b424648ab7ce, 0xcb1d4f7a03fbc9e3, 0x12d931429800d019}}, - {{0x00c67799d337594f, 0x5e3c5140b23aa47b, 0x44182854e35ff395, 0x1b4f92314359a012}}}, -{{{0x3e5c109d89150951, 0x39cefa912de9696a, 0x20eae43f975f3020, 0x239b572a7f132dae}}, - {{0x33cf3030a49866b1, 0x251f73d2215f4859, 0xab82aa4051def4f6, 0x5ff191d56f9a23f6}}, - {{0x819ed433ac2d9068, 0x2883ab795fc98523, 0xef4572805593eb3d, 0x020c526a758f36cb}}}, -{{{0x779834f89ed8dbbc, 0xc8f2aaf9dc7ca46c, 0xa9524cdca3e1b074, 0x02aacc4615313877}}, - {{0xe931ef59f042cc89, 0x2c589c9d8e124bb6, 0xadc8e18aaec75997, 0x452cfe0a5602c50c}}, - {{0x86a0f7a0647877df, 0xbbc464270e607c9f, 0xab17ea25f1fb11c9, 0x4cfb7d7b304b877b}}}, -{{{0x72b43d6cb89b75fe, 0x54c694d99c6adc80, 0xb8c3aa373ee34c9f, 0x14b4622b39075364}}, - {{0xe28699c29789ef12, 0x2b6ecd71df57190d, 0xc343c857ecc970d0, 0x5b1d4cbc434d3ac5}}, - {{0xb6fb2615cc0a9f26, 0x3a4f0e2bb88dcce5, 0x1301498b3369a705, 0x2f98f71258592dd1}}}, -{{{0x0c94a74cb50f9e56, 0x5b1ff4a98e8e1320, 0x9a2acc2182300f67, 0x3a6ae249d806aaf9}}, - {{0x2e12ae444f54a701, 0xfcfe3ef0a9cbd7de, 0xcebf890d75835de0, 0x1d8062e9e7614554}}, - {{0x657ada85a9907c5a, 0x1a0ea8b591b90f62, 0x8d0e1dfbdf34b4e9, 0x298b8ce8aef25ff3}}}, -{{{0x2a927953eff70cb2, 0x4b89c92a79157076, 0x9418457a30a7cf6a, 0x34b8a8404d5ce485}}, - {{0x837a72ea0a2165de, 0x3fab07b40bcf79f6, 0x521636c77738ae70, 0x6ba6271803a7d7dc}}, - {{0xc26eecb583693335, 0xd5a813df63b5fefd, 0xa293aa9aa4b22573, 0x71d62bdd465e1c6a}}}, -{{{0x6533cc28d378df80, 0xf6db43790a0fa4b4, 0xe3645ff9f701da5a, 0x74d5f317f3172ba4}}, - {{0xcd2db5dab1f75ef5, 0xd77f95cf16b065f5, 0x14571fea3f49f085, 0x1c333621262b2b3d}}, - {{0xa86fe55467d9ca81, 0x398b7c752b298c37, 0xda6d0892e3ac623b, 0x4aebcc4547e9d98c}}}, -{{{0x53175a7205d21a77, 0xb0c04422d3b934d4, 0xadd9f24bdd5deadc, 0x074f46e69f10ff8c}}, - {{0x0de9b204a059a445, 0xe15cb4aa4b17ad0f, 0xe1bbec521f79c557, 0x2633f1b9d071081b}}, - {{0xc1fb4177018b9910, 0xa6ea20dc6c0fe140, 0xd661f3e74354c6ff, 0x5ecb72e6f1a3407a}}}, -{{{0xa515a31b2259fb4e, 0x0960f3972bcac52f, 0xedb52fec8d3454cb, 0x382e2720c476c019}}, - {{0xfeeae106e8e86997, 0x9863337f98d09383, 0x9470480eaa06ebef, 0x038b6898d4c5c2d0}}, - {{0xf391c51d8ace50a6, 0x3142d0b9ae2d2948, 0xdb4d5a1a7f24ca80, 0x21aeba8b59250ea8}}}, -{{{0x24f13b34cf405530, 0x3c44ea4a43088af7, 0x5dd5c5170006a482, 0x118eb8f8890b086d}}, - {{0x53853600f0087f23, 0x4c461879da7d5784, 0x6af303deb41f6860, 0x0a3c16c5c27c18ed}}, - {{0x17e49c17cc947f3d, 0xccc6eda6aac1d27b, 0xdf6092ceb0f08e56, 0x4909b3e22c67c36b}}}, -{{{0x9c9c85ea63fe2e89, 0xbe1baf910e9412ec, 0x8f7baa8a86fbfe7b, 0x0fb17f9fef968b6c}}, - {{0x59a16676706ff64e, 0x10b953dd0d86a53d, 0x5848e1e6ce5c0b96, 0x2d8b78e712780c68}}, - {{0x79d5c62eafc3902b, 0x773a215289e80728, 0xc38ae640e10120b9, 0x09ae23717b2b1a6d}}}, -{{{0xbb6a192a4e4d083c, 0x34ace0630029e192, 0x98245a59aafabaeb, 0x6d9c8a9ada97faac}}, - {{0x10ab8fa1ad32b1d0, 0xe9aced1be2778b24, 0xa8856bc0373de90f, 0x66f35ddddda53996}}, - {{0xd27d9afb24997323, 0x1bb7e07ef6f01d2e, 0x2ba7472df52ecc7f, 0x03019b4f646f9dc8}}}, -{{{0x04a186b5565345cd, 0xeee76610bcc4116a, 0x689c73b478fb2a45, 0x387dcbff65697512}}, - {{0xaf09b214e6b3dc6b, 0x3f7573b5ad7d2f65, 0xd019d988100a23b0, 0x392b63a58b5c35f7}}, - {{0x4093addc9c07c205, 0xc565be15f532c37e, 0x63dbecfd1583402a, 0x61722b4aef2e032e}}}, -{{{0x0012aafeecbd47af, 0x55a266fb1cd46309, 0xf203eb680967c72c, 0x39633944ca3c1429}}, - {{0xd6b07a5581cb0e3c, 0x290ff006d9444969, 0x08680b6a16dcda1f, 0x5568d2b75a06de59}}, - {{0x8d0cb88c1b37cfe1, 0x05b6a5a3053818f3, 0xf2e9bc04b787d959, 0x6beba1249add7f64}}}, -{{{0x1d06005ca5b1b143, 0x6d4c6bb87fd1cda2, 0x6ef5967653fcffe7, 0x097c29e8c1ce1ea5}}, - {{0x5c3cecb943f5a53b, 0x9cc9a61d06c08df2, 0xcfba639a85895447, 0x5a845ae80df09fd5}}, - {{0x4ce97dbe5deb94ca, 0x38d0a4388c709c48, 0xc43eced4a169d097, 0x0a1249fff7e587c3}}}, -{{{0x12f0071b276d01c9, 0xe7b8bac586c48c70, 0x5308129b71d6fba9, 0x5d88fbf95a3db792}}, - {{0x0b408d9e7354b610, 0x806b32535ba85b6e, 0xdbe63a034a58a207, 0x173bd9ddc9a1df2c}}, - {{0x2b500f1efe5872df, 0x58d6582ed43918c1, 0xe6ed278ec9673ae0, 0x06e1cd13b19ea319}}}, -{{{0x40d0ad516f166f23, 0x118e32931fab6abe, 0x3fe35e14a04d088e, 0x3080603526e16266}}, - {{0x472baf629e5b0353, 0x3baa0b90278d0447, 0x0c785f469643bf27, 0x7f3a6a1a8d837b13}}, - {{0xf7e644395d3d800b, 0x95a8d555c901edf6, 0x68cd7830592c6339, 0x30d0fded2e51307e}}}, -{{{0xe0594d1af21233b3, 0x1bdbe78ef0cc4d9c, 0x6965187f8f499a77, 0x0a9214202c099868}}, - {{0x9cb4971e68b84750, 0xa09572296664bbcf, 0x5c8de72672fa412b, 0x4615084351c589d9}}, - {{0xbc9019c0aeb9a02e, 0x55c7110d16034cae, 0x0e6df501659932ec, 0x3bca0d2895ca5dfe}}}, -{{{0x40f031bc3c5d62a4, 0x19fc8b3ecff07a60, 0x98183da2130fb545, 0x5631deddae8f13cd}}, - {{0x9c688eb69ecc01bf, 0xf0bc83ada644896f, 0xca2d955f5f7a9fe2, 0x4ea8b4038df28241}}, - {{0x2aed460af1cad202, 0x46305305a48cee83, 0x9121774549f11a5f, 0x24ce0930542ca463}}}, -{{{0x1fe890f5fd06c106, 0xb5c468355d8810f2, 0x827808fe6e8caf3e, 0x41d4e3c28a06d74b}}, - {{0x3fcfa155fdf30b85, 0xd2f7168e36372ea4, 0xb2e064de6492f844, 0x549928a7324f4280}}, - {{0xf26e32a763ee1a2e, 0xae91e4b7d25ffdea, 0xbc3bd33bd17f4d69, 0x491b66dec0dcff6a}}}, -{{{0x98f5b13dc7ea32a7, 0xe3d5f8cc7e16db98, 0xac0abf52cbf8d947, 0x08f338d0c85ee4ac}}, - {{0x75f04a8ed0da64a1, 0xed222caf67e2284b, 0x8234a3791f7b7ba4, 0x4cf6b8b0b7018b67}}, - {{0xc383a821991a73bd, 0xab27bc01df320c7a, 0xc13d331b84777063, 0x530d4a82eb078a99}}}, -{{{0x004c3630e1f94825, 0x7e2d78268cab535a, 0xc7482323cc84ff8b, 0x65ea753f101770b9}}, - {{0x6d6973456c9abf9e, 0x257fb2fc4900a880, 0x2bacf412c8cfb850, 0x0db3e7e00cbfbd5b}}, - {{0x3d66fc3ee2096363, 0x81d62c7f61b5cb6b, 0x0fbe044213443b1a, 0x02a4ec1921e1a1db}}}, -{{{0x5ce6259a3b24b8a2, 0xb8577acc45afa0b8, 0xcccbe6e88ba07037, 0x3d143c51127809bf}}, - {{0xf5c86162f1cf795f, 0x118c861926ee57f2, 0x172124851c063578, 0x36d12b5dec067fcf}}, - {{0x126d279179154557, 0xd5e48f5cfc783a0a, 0x36bdb6e8df179bac, 0x2ef517885ba82859}}}, -{{{0x88bd438cd11e0d4a, 0x30cb610d43ccf308, 0xe09a0e3791937bcc, 0x4559135b25b1720c}}, - {{0x1ea436837c6da1e9, 0xf9c189af1fb9bdbe, 0x303001fcce5dd155, 0x28a7c99ebc57be52}}, - {{0xb8fd9399e8d19e9d, 0x908191cb962423ff, 0xb2b948d747c742a3, 0x37f33226d7fb44c4}}}, -{{{0x0dae8767b55f6e08, 0x4a43b3b35b203a02, 0xe3725a6e80af8c79, 0x0f7a7fd1705fa7a3}}, - {{0x33912553c821b11d, 0x66ed42c241e301df, 0x066fcc11104222fd, 0x307a3b41c192168f}}, - {{0x8eeb5d076eb55ce0, 0x2fc536bfaa0d925a, 0xbe81830fdcb6c6e8, 0x556c7045827baf52}}}, -{{{0x8e2b517302e9d8b7, 0xe3e52269248714e8, 0xbd4fbd774ca960b5, 0x6f4b4199c5ecada9}}, - {{0xb94b90022bf44406, 0xabd4237eff90b534, 0x7600a960faf86d3a, 0x2f45abdac2322ee3}}, - {{0x61af4912c8ef8a6a, 0xe58fa4fe43fb6e5e, 0xb5afcc5d6fd427cf, 0x6a5393281e1e11eb}}}, -{{{0xf3da5139a5d1ee89, 0x8145457cff936988, 0x3f622fed00e188c4, 0x0f513815db8b5a3d}}, - {{0x0fff04fe149443cf, 0x53cac6d9865cddd7, 0x31385b03531ed1b7, 0x5846a27cacd1039d}}, - {{0x4ff5cdac1eb08717, 0x67e8b29590f2e9bc, 0x44093b5e237afa99, 0x0d414bed8708b8b2}}}, -{{{0xcfb68265fd0e75f6, 0xe45b3e28bb90e707, 0x7242a8de9ff92c7a, 0x685b3201933202dd}}, - {{0x81886a92294ac9e8, 0x23162b45d55547be, 0x94cfbc4403715983, 0x50eb8fdb134bc401}}, - {{0xc0b73ec6d6b330cd, 0x84e44807132faff1, 0x732b7352c4a5dee1, 0x5d7c7cf1aa7cd2d2}}}, -{{{0xaf3b46bf7a4aafa2, 0xb78705ec4d40d411, 0x114f0c6aca7c15e3, 0x3f364faaa9489d4d}}, - {{0x33d1013e9b73a562, 0x925cef5748ec26e1, 0xa7fce614dd468058, 0x78b0fad41e9aa438}}, - {{0xbf56a431ed05b488, 0xa533e66c9c495c7e, 0xe8652baf87f3651a, 0x0241800059d66c33}}}, -{{{0xceb077fea37a5be4, 0xdb642f02e5a5eeb7, 0xc2e6d0c5471270b8, 0x4771b65538e4529c}}, - {{0x28350c7dcf38ea01, 0x7c6cdbc0b2917ab6, 0xace7cfbe857082f7, 0x4d2845aba2d9a1e0}}, - {{0xbb537fe0447070de, 0xcba744436dd557df, 0xd3b5a3473600dbcb, 0x4aeabbe6f9ffd7f8}}}, -{{{0x4630119e40d8f78c, 0xa01a9bc53c710e11, 0x486d2b258910dd79, 0x1e6c47b3db0324e5}}, - {{0x6a2134bcc4a9c8f2, 0xfbf8fd1c8ace2e37, 0x000ae3049911a0ba, 0x046e3a616bc89b9e}}, - {{0x14e65442f03906be, 0x4a019d54e362be2a, 0x68ccdfec8dc230c7, 0x7cfb7e3faf6b861c}}}, -{{{0x4637974e8c58aedc, 0xb9ef22fbabf041a4, 0xe185d956e980718a, 0x2f1b78fab143a8a6}}, - {{0x96eebffb305b2f51, 0xd3f938ad889596b8, 0xf0f52dc746d5dd25, 0x57968290bb3a0095}}, - {{0xf71ab8430a20e101, 0xf393658d24f0ec47, 0xcf7509a86ee2eed1, 0x7dc43e35dc2aa3e1}}}, -{{{0x85966665887dd9c3, 0xc90f9b314bb05355, 0xc6e08df8ef2079b1, 0x7ef72016758cc12f}}, - {{0x5a782a5c273e9718, 0x3576c6995e4efd94, 0x0f2ed8051f237d3e, 0x044fb81d82d50a99}}, - {{0xc1df18c5a907e3d9, 0x57b3371dce4c6359, 0xca704534b201bb49, 0x7f79823f9c30dd2e}}}, -{{{0x8334d239a3b513e8, 0xc13670d4b91fa8d8, 0x12b54136f590bd33, 0x0a4e0373d784d9b4}}, - {{0x6a9c1ff068f587ba, 0x0827894e0050c8de, 0x3cbf99557ded5be7, 0x64a9b0431c06d6f0}}, - {{0x2eb3d6a15b7d2919, 0xb0b4f6a0d53a8235, 0x7156ce4389a45d47, 0x071a7d0ace18346c}}}, -{{{0xd3072daac887ba0b, 0x01262905bfa562ee, 0xcf543002c0ef768b, 0x2c3bcc7146ea7e9c}}, - {{0xcc0c355220e14431, 0x0d65950709b15141, 0x9af5621b209d5f36, 0x7c69bcf7617755d3}}, - {{0x07f0d7eb04e8295f, 0x10db18252f50f37d, 0xe951a9a3171798d7, 0x6f5a9a7322aca51d}}}, -{{{0x8ba1000c2f41c6c5, 0xc49f79c10cfefb9b, 0x4efa47703cc51c9f, 0x494e21a2e147afca}}, - {{0xe729d4eba3d944be, 0x8d9e09408078af9e, 0x4525567a47869c03, 0x02ab9680ee8d3b24}}, - {{0xefa48a85dde50d9a, 0x219a224e0fb9a249, 0xfa091f1dd91ef6d9, 0x6b5d76cbea46bb34}}}, -{{{0x8857556cec0cd994, 0x6472dc6f5cd01dba, 0xaf0169148f42b477, 0x0ae333f685277354}}, - {{0xe0f941171e782522, 0xf1e6ae74036936d3, 0x408b3ea2d0fcc746, 0x16fb869c03dd313e}}, - {{0x288e199733b60962, 0x24fc72b4d8abe133, 0x4811f7ed0991d03e, 0x3f81e38b8f70d075}}}, -{{{0x7f910fcc7ed9affe, 0x545cb8a12465874b, 0xa8397ed24b0c4704, 0x50510fc104f50993}}, - {{0x0adb7f355f17c824, 0x74b923c3d74299a4, 0xd57c3e8bcbf8eaf7, 0x0ad3e2d34cdedc3d}}, - {{0x6f0c0fc5336e249d, 0x745ede19c331cfd9, 0xf2d6fd0009eefe1c, 0x127c158bf0fa1ebe}}}, -{{{0xf6197c422e9879a2, 0xa44addd452ca3647, 0x9b413fc14b4eaccb, 0x354ef87d07ef4f68}}, - {{0xdea28fc4ae51b974, 0x1d9973d3744dfe96, 0x6240680b873848a8, 0x4ed82479d167df95}}, - {{0xfee3b52260c5d975, 0x50352efceb41b0b8, 0x8808ac30a9f6653c, 0x302d92d20539236d}}}, -{{{0x4c59023fcb3efb7c, 0x6c2fcb99c63c2a94, 0xba4190e2c3c7e084, 0x0e545daea51874d9}}, - {{0x957b8b8b0df53c30, 0x2a1c770a8e60f098, 0xbbc7a670345796de, 0x22a48f9a90c99bc9}}, - {{0x6b7dc0dc8d3fac58, 0x5497cd6ce6e42bfd, 0x542f7d1bf400d305, 0x4159f47f048d9136}}}, -{{{0x20ad660839e31e32, 0xf81e1bd58405be50, 0xf8064056f4dabc69, 0x14d23dd4ce71b975}}, - {{0x748515a8bbd24839, 0x77128347afb02b55, 0x50ba2ac649a2a17f, 0x060525513ad730f1}}, - {{0xf2398e098aa27f82, 0x6d7982bb89a1b024, 0xfa694084214dd24c, 0x71ab966fa32301c3}}}, -{{{0x2dcbd8e34ded02fc, 0x1151f3ec596f22aa, 0xbca255434e0328da, 0x35768fbe92411b22}}, - {{0xb1088a0702809955, 0x43b273ea0b43c391, 0xca9b67aefe0686ed, 0x605eecbf8335f4ed}}, - {{0x83200a656c340431, 0x9fcd71678ee59c2f, 0x75d4613f71300f8a, 0x7a912faf60f542f9}}}, -{{{0xb204585e5edc1a43, 0x9f0e16ee5897c73c, 0x5b82c0ae4e70483c, 0x624a170e2bddf9be}}, - {{0x253f4f8dfa2d5597, 0x25e49c405477130c, 0x00c052e5996b1102, 0x33cb966e33bb6c4a}}, - {{0x597028047f116909, 0x828ac41c1e564467, 0x70417dbde6217387, 0x721627aefbac4384}}}, -{{{0x97d03bc38736add5, 0x2f1422afc532b130, 0x3aa68a057101bbc4, 0x4c946cf7e74f9fa7}}, - {{0xfd3097bc410b2f22, 0xf1a05da7b5cfa844, 0x61289a1def57ca74, 0x245ea199bb821902}}, - {{0xaedca66978d477f8, 0x1898ba3c29117fe1, 0xcf73f983720cbd58, 0x67da12e6b8b56351}}}, -{{{0x7067e187b4bd6e07, 0x6e8f0203c7d1fe74, 0x93c6aa2f38c85a30, 0x76297d1f3d75a78a}}, - {{0x2b7ef3d38ec8308c, 0x828fd7ec71eb94ab, 0x807c3b36c5062abd, 0x0cb64cb831a94141}}, - {{0x3030fc33534c6378, 0xb9635c5ce541e861, 0x15d9a9bed9b2c728, 0x49233ea3f3775dcb}}}, -{{{0x629398fa8dbffc3a, 0xe12fe52dd54db455, 0xf3be11dfdaf25295, 0x628b140dce5e7b51}}, - {{0x7b3985fe1c9f249b, 0x4fd6b2d5a1233293, 0xceb345941adf4d62, 0x6987ff6f542de50c}}, - {{0x47e241428f83753c, 0x6317bebc866af997, 0xdabb5b433d1a9829, 0x074d8d245287fb2d}}}, -{{{0x8337d9cd440bfc31, 0x729d2ca1af318fd7, 0xa040a4a4772c2070, 0x46002ef03a7349be}}, - {{0x481875c6c0e31488, 0x219429b2e22034b4, 0x7223c98a31283b65, 0x3420d60b342277f9}}, - {{0xfaa23adeaffe65f7, 0x78261ed45be0764c, 0x441c0a1e2f164403, 0x5aea8e567a87d395}}}, -{{{0x7813c1a2bca4283d, 0xed62f091a1863dd9, 0xaec7bcb8c268fa86, 0x10e5d3b76f1cae4c}}, - {{0x2dbc6fb6e4e0f177, 0x04e1bf29a4bd6a93, 0x5e1966d4787af6e8, 0x0edc5f5eb426d060}}, - {{0x5453bfd653da8e67, 0xe9dc1eec24a9f641, 0xbf87263b03578a23, 0x45b46c51361cba72}}}, -{{{0xa9402abf314f7fa1, 0xe257f1dc8e8cf450, 0x1dbbd54b23a8be84, 0x2177bfa36dcb713b}}, - {{0xce9d4ddd8a7fe3e4, 0xab13645676620e30, 0x4b594f7bb30e9958, 0x5c1c0aef321229df}}, - {{0x37081bbcfa79db8f, 0x6048811ec25f59b3, 0x087a76659c832487, 0x4ae619387d8ab5bb}}}, -{{{0x8ddbf6aa5344a32e, 0x7d88eab4b41b4078, 0x5eb0eb974a130d60, 0x1a00d91b17bf3e03}}, - {{0x61117e44985bfb83, 0xfce0462a71963136, 0x83ac3448d425904b, 0x75685abe5ba43d64}}, - {{0x6e960933eb61f2b2, 0x543d0fa8c9ff4952, 0xdf7275107af66569, 0x135529b623b0e6aa}}}, -{{{0x18f0dbd7add1d518, 0x979f7888cfc11f11, 0x8732e1f07114759b, 0x79b5b81a65ca3a01}}, - {{0xf5c716bce22e83fe, 0xb42beb19e80985c1, 0xec9da63714254aae, 0x5972ea051590a613}}, - {{0x0fd4ac20dc8f7811, 0x9a9ad294ac4d4fa8, 0xc01b2d64b3360434, 0x4f7e9c95905f3bdb}}}, -{{{0x62674bbc5781302e, 0xd8520f3989addc0f, 0x8c2999ae53fbd9c6, 0x31993ad92e638e4c}}, - {{0x71c8443d355299fe, 0x8bcd3b1cdbebead7, 0x8092499ef1a49466, 0x1942eec4a144adc8}}, - {{0x7dac5319ae234992, 0x2c1b3d910cea3e92, 0x553ce494253c1122, 0x2a0a65314ef9ca75}}}, -{{{0x2db7937ff7f927c2, 0xdb741f0617d0a635, 0x5982f3a21155af76, 0x4cf6e218647c2ded}}, - {{0xcf361acd3c1c793a, 0x2f9ebcac5a35bc3b, 0x60e860e9a8cda6ab, 0x055dc39b6dea1a13}}, - {{0xb119227cc28d5bb6, 0x07e24ebc774dffab, 0xa83c78cee4a32c89, 0x121a307710aa24b6}}}, -{{{0xe4db5d5e9f034a97, 0xe153fc093034bc2d, 0x460546919551d3b1, 0x333fc76c7a40e52d}}, - {{0xd659713ec77483c9, 0x88bfe077b82b96af, 0x289e28231097bcd3, 0x527bb94a6ced3a9b}}, - {{0x563d992a995b482e, 0x3405d07c6e383801, 0x485035de2f64d8e5, 0x6b89069b20a7a9f7}}}, -{{{0x812aa0416270220d, 0x995a89faf9245b4e, 0xffadc4ce5072ef05, 0x23bc2103aa73eb73}}, - {{0x4082fa8cb5c7db77, 0x068686f8c734c155, 0x29e6c8d9f6e7a57e, 0x0473d308a7639bcf}}, - {{0xcaee792603589e05, 0x2b4b421246dcc492, 0x02a1ef74e601a94f, 0x102f73bfde04341a}}}, -{{{0xb5a2d50c7ec20d3e, 0xc64bdd6ea0c97263, 0x56e89052c1ff734d, 0x4929c6f72b2ffaba}}, - {{0x358ecba293a36247, 0xaf8f9862b268fd65, 0x412f7e9968a01c89, 0x5786f312cd754524}}, - {{0x337788ffca14032c, 0xf3921028447f1ee3, 0x8b14071f231bccad, 0x4c817b4bf2344783}}}, -{{{0x0ff853852871b96e, 0xe13e9fab60c3f1bb, 0xeefd595325344402, 0x0a37c37075b7744b}}, - {{0x413ba057a40b4484, 0xba4c2e1a4f5f6a43, 0x614ba0a5aee1d61c, 0x78a1531a8b05dc53}}, - {{0x6cbdf1703ad0562b, 0x8ecf4830c92521a3, 0xdaebd303fd8424e7, 0x72ad82a42e5ec56f}}}, -{{{0x3f9e8e35bafb65f6, 0x39d69ec8f27293a1, 0x6cb8cd958cf6a3d0, 0x1734778173adae6d}}, - {{0xc368939167024bc3, 0x8e69d16d49502fda, 0xfcf2ec3ce45f4b29, 0x065f669ea3b4cbc4}}, - {{0x8a00aec75532db4d, 0xb869a4e443e31bb1, 0x4a0f8552d3a7f515, 0x19adeb7c303d7c08}}}, -{{{0xc720cb6153ead9a3, 0x55b2c97f512b636e, 0xb1e35b5fd40290b1, 0x2fd9ccf13b530ee2}}, - {{0x9d05ba7d43c31794, 0x2470c8ff93322526, 0x8323dec816197438, 0x2852709881569b53}}, - {{0x07bd475b47f796b8, 0xd2c7b013542c8f54, 0x2dbd23f43b24f87e, 0x6551afd77b0901d6}}}, -{{{0x4546baaf54aac27f, 0xf6f66fecb2a45a28, 0x582d1b5b562bcfe8, 0x44b123f3920f785f}}, - {{0x68a24ce3a1d5c9ac, 0xbb77a33d10ff6461, 0x0f86ce4425d3166e, 0x56507c0950b9623b}}, - {{0x1206f0b7d1713e63, 0x353fe3d915bafc74, 0x194ceb970ad9d94d, 0x62fadd7cf9d03ad3}}}, -{{{0xc6b5967b5598a074, 0x5efe91ce8e493e25, 0xd4b72c4549280888, 0x20ef1149a26740c2}}, - {{0x3cd7bc61e7ce4594, 0xcd6b35a9b7dd267e, 0xa080abc84366ef27, 0x6ec7c46f59c79711}}, - {{0x2f07ad636f09a8a2, 0x8697e6ce24205e7d, 0xc0aefc05ee35a139, 0x15e80958b5f9d897}}}, -{{{0x25a5ef7d0c3e235b, 0x6c39c17fbe134ee7, 0xc774e1342dc5c327, 0x021354b892021f39}}, - {{0x4dd1ed355bb061c4, 0x42dc0cef941c0700, 0x61305dc1fd86340e, 0x56b2cc930e55a443}}, - {{0x1df79da6a6bfc5a2, 0x02f3a2749fde4369, 0xb323d9f2cda390a7, 0x7be0847b8774d363}}}, -{{{0x8c99cc5a8b3f55c3, 0x0611d7253fded2a0, 0xed2995ff36b70a36, 0x1f699a54d78a2619}}, - {{0x1466f5af5307fa11, 0x817fcc7ded6c0af2, 0x0a6de44ec3a4a3fb, 0x74071475bc927d0b}}, - {{0xe77292f373e7ea8a, 0x296537d2cb045a31, 0x1bd0653ed3274fde, 0x2f9a2c4476bd2966}}}, -{{{0xeb18b9ab7f5745c6, 0x023a8aee5787c690, 0xb72712da2df7afa9, 0x36597d25ea5c013d}}, - {{0xa2b4dae0b5511c9a, 0x7ac860292bffff06, 0x981f375df5504234, 0x3f6bd725da4ea12d}}, - {{0x734d8d7b106058ac, 0xd940579e6fc6905f, 0x6466f8f99202932d, 0x7b7ecc19da60d6d0}}}, -{{{0x78c2373c695c690d, 0xdd252e660642906e, 0x951d44444ae12bd2, 0x4235ad7601743956}}, - {{0x6dae4a51a77cfa9b, 0x82263654e7a38650, 0x09bbffcd8f2d82db, 0x03bedc661bf5caba}}, - {{0x6258cb0d078975f5, 0x492942549189f298, 0xa0cab423e2e36ee4, 0x0e7ce2b0cdf066a1}}}, -{{{0xc494643ac48c85a3, 0xfd361df43c6139ad, 0x09db17dd3ae94d48, 0x666e0a5d8fb4674a}}, - {{0xfea6fedfd94b70f9, 0xf130c051c1fcba2d, 0x4882d47e7f2fab89, 0x615256138aeceeb5}}, - {{0x2abbf64e4870cb0d, 0xcd65bcf0aa458b6b, 0x9abe4eba75e8985d, 0x7f0bc810d514dee4}}}, -{{{0xb9006ba426f4136f, 0x8d67369e57e03035, 0xcbc8dfd94f463c28, 0x0d1f8dbcf8eedbf5}}, - {{0x83ac9dad737213a0, 0x9ff6f8ba2ef72e98, 0x311e2edd43ec6957, 0x1d3a907ddec5ab75}}, - {{0xba1693313ed081dc, 0x29329fad851b3480, 0x0128013c030321cb, 0x00011b44a31bfde3}}}, -{{{0x3fdfa06c3fc66c0c, 0x5d40e38e4dd60dd2, 0x7ae38b38268e4d71, 0x3ac48d916e8357e1}}, - {{0x16561f696a0aa75c, 0xc1bf725c5852bd6a, 0x11a8dd7f9a7966ad, 0x63d988a2d2851026}}, - {{0x00120753afbd232e, 0xe92bceb8fdd8f683, 0xf81669b384e72b91, 0x33fad52b2368a066}}}, -{{{0x540649c6c5e41e16, 0x0af86430333f7735, 0xb2acfcd2f305e746, 0x16c0f429a256dca7}}, - {{0x8d2cc8d0c422cfe8, 0x072b4f7b05a13acb, 0xa3feb6e6ecf6a56f, 0x3cc355ccb90a71e2}}, - {{0xe9b69443903e9131, 0xb8a494cb7a5637ce, 0xc87cd1a4baba9244, 0x631eaf426bae7568}}}, -{{{0xb3e90410da66fe9f, 0x85dd4b526c16e5a6, 0xbc3d97611ef9bf83, 0x5599648b1ea919b5}}, - {{0x47d975b9a3700de8, 0x7280c5fbe2f80552, 0x53658f2732e45de1, 0x431f2c7f665f80b5}}, - {{0xd6026344858f7b19, 0x14ab352fa1ea514a, 0x8900441a2090a9d7, 0x7b04715f91253b26}}}, -{{{0x83edbd28acf6ae43, 0x86357c8b7d5c7ab4, 0xc0404769b7eb2c44, 0x59b37bf5c2f6583f}}, - {{0xb376c280c4e6bac6, 0x970ed3dd6d1d9b0b, 0xb09a9558450bf944, 0x48d0acfa57cde223}}, - {{0xb60f26e47dabe671, 0xf1d1a197622f3a37, 0x4208ce7ee9960394, 0x16234191336d3bdb}}}, -{{{0xf19aeac733a63aef, 0x2c7fba5d4442454e, 0x5da87aa04795e441, 0x413051e1a4e0b0f5}}, - {{0x852dd1fd3d578bbe, 0x2b65ce72c3286108, 0x658c07f4eace2273, 0x0933f804ec38ab40}}, - {{0xa7ab69798d496476, 0x8121aadefcb5abc8, 0xa5dc12ef7b539472, 0x07fd47065e45351a}}}, -{{{0xc8583c3d258d2bcd, 0x17029a4daf60b73f, 0xfa0fc9d6416a3781, 0x1c1e5fba38b3fb23}}, - {{0x304211559ae8e7c3, 0xf281b229944882a5, 0x8a13ac2e378250e4, 0x014afa0954ba48f4}}, - {{0xcb3197001bb3666c, 0x330060524bffecb9, 0x293711991a88233c, 0x291884363d4ed364}}}, -{{{0x033c6805dc4babfa, 0x2c15bf5e5596ecc1, 0x1bc70624b59b1d3b, 0x3ede9850a19f0ec5}}, - {{0xfb9d37c3bc1ab6eb, 0x02be14534d57a240, 0xf4d73415f8a5e1f6, 0x5964f4300ccc8188}}, - {{0xe44a23152d096800, 0x5c08c55970866996, 0xdf2db60a46affb6e, 0x579155c1f856fd89}}}, -{{{0x96324edd12e0c9ef, 0x468b878df2420297, 0x199a3776a4f573be, 0x1e7fbcf18e91e92a}}, - {{0xb5f16b630817e7a6, 0x808c69233c351026, 0x324a983b54cef201, 0x53c092084a485345}}, - {{0xd2d41481f1cbafbf, 0x231d2db6716174e5, 0x0b7d7656e2a55c98, 0x3e955cd82aa495f6}}}, -{{{0xe48f535e3ed15433, 0xd075692a0d7270a3, 0x40fbd21daade6387, 0x14264887cf4495f5}}, - {{0xab39f3ef61bb3a3f, 0x8eb400652eb9193e, 0xb5de6ecc38c11f74, 0x654d7e9626f3c49f}}, - {{0xe564cfdd5c7d2ceb, 0x82eeafded737ccb9, 0x6107db62d1f9b0ab, 0x0b6baac3b4358dbb}}}, -{{{0x7ae62bcb8622fe98, 0x47762256ceb891af, 0x1a5a92bcf2e406b4, 0x7d29401784e41501}}, - {{0x204abad63700a93b, 0xbe0023d3da779373, 0xd85f0346633ab709, 0x00496dc490820412}}, - {{0x1c74b88dc27e6360, 0x074854268d14850c, 0xa145fb7b3e0dcb30, 0x10843f1b43803b23}}}, -{{{0xc5f90455376276dd, 0xce59158dd7645cd9, 0x92f65d511d366b39, 0x11574b6e526996c4}}, - {{0xd56f672de324689b, 0xd1da8aedb394a981, 0xdd7b58fe9168cfed, 0x7ce246cd4d56c1e8}}, - {{0xb8f4308e7f80be53, 0x5f3cb8cb34a9d397, 0x18a961bd33cc2b2c, 0x710045fb3a9af671}}}, -{{{0x73f93d36101b95eb, 0xfaef33794f6f4486, 0x5651735f8f15e562, 0x7fa3f19058b40da1}}, - {{0xa03fc862059d699e, 0x2370cfa19a619e69, 0xc4fe3b122f823deb, 0x1d1b056fa7f0844e}}, - {{0x1bc64631e56bf61f, 0xd379ab106e5382a3, 0x4d58c57e0540168d, 0x566256628442d8e4}}}, -{{{0xb9e499def6267ff6, 0x7772ca7b742c0843, 0x23a0153fe9a4f2b1, 0x2cdfdfecd5d05006}}, - {{0xdd499cd61ff38640, 0x29cd9bc3063625a0, 0x51e2d8023dd73dc3, 0x4a25707a203b9231}}, - {{0x2ab7668a53f6ed6a, 0x304242581dd170a1, 0x4000144c3ae20161, 0x5721896d248e49fc}}}, -{{{0x0b6e5517fd181bae, 0x9022629f2bb963b4, 0x5509bce932064625, 0x578edd74f63c13da}}, - {{0x285d5091a1d0da4e, 0x4baa6fa7b5fe3e08, 0x63e5177ce19393b3, 0x03c935afc4b030fd}}, - {{0x997276c6492b0c3d, 0x47ccc2c4dfe205fc, 0xdcd29b84dd623a3c, 0x3ec2ab590288c7a2}}}, -{{{0xa1a0d27be4d87bb9, 0xa98b4deb61391aed, 0x99a0ddd073cb9b83, 0x2dd5c25a200fcace}}, - {{0xa7213a09ae32d1cb, 0x0f2b87df40f5c2d5, 0x0baea4c6e81eab29, 0x0e1bf66c6adbac5e}}, - {{0xe2abd5e9792c887e, 0x1a020018cb926d5d, 0xbfba69cdbaae5f1e, 0x730548b35ae88f5f}}}, -{{{0xc43551a3cba8b8ee, 0x65a26f1db2115f16, 0x760f4f52ab8c3850, 0x3043443b411db8ca}}, - {{0x805b094ba1d6e334, 0xbf3ef17709353f19, 0x423f06cb0622702b, 0x585a2277d87845dd}}, - {{0xa18a5f8233d48962, 0x6698c4b5ec78257f, 0xa78e6fa5373e41ff, 0x7656278950ef981f}}}, -{{{0x38c3cf59d51fc8c0, 0x9bedd2fd0506b6f2, 0x26bf109fab570e8f, 0x3f4160a8c1b846a6}}, - {{0xe17073a3ea86cf9d, 0x3a8cfbb707155fdc, 0x4853e7fc31838a8e, 0x28bbf484b613f616}}, - {{0xf2612f5c6f136c7c, 0xafead107f6dd11be, 0x527e9ad213de6f33, 0x1e79cb358188f75d}}}, -{{{0x013436c3eef7e3f1, 0x828b6a7ffe9e10f8, 0x7ff908e5bcf9defc, 0x65d7951b3a3b3831}}, - {{0x77e953d8f5e08181, 0x84a50c44299dded9, 0xdc6c2d0c864525e5, 0x478ab52d39d1f2f4}}, - {{0x66a6a4d39252d159, 0xe5dde1bc871ac807, 0xb82c6b40a6c1c96f, 0x16d87a411a212214}}}, -{{{0xb3bd7e5a42066215, 0x879be3cd0c5a24c1, 0x57c05db1d6f994b7, 0x28f87c8165f38ca6}}, - {{0xfba4d5e2d54e0583, 0xe21fafd72ebd99fa, 0x497ac2736ee9778f, 0x1f990b577a5a6dde}}, - {{0xa3344ead1be8f7d6, 0x7d1e50ebacea798f, 0x77c6569e520de052, 0x45882fe1534d6d3e}}}, -{{{0x6669345d757983d6, 0x62b6ed1117aa11a6, 0x7ddd1857985e128f, 0x688fe5b8f626f6dd}}, - {{0xd8ac9929943c6fe4, 0xb5f9f161a38392a2, 0x2699db13bec89af3, 0x7dcf843ce405f074}}, - {{0x6c90d6484a4732c0, 0xd52143fdca563299, 0xb3be28c3915dc6e1, 0x6739687e7327191b}}}, -{{{0x9f65c5ea200814cf, 0x840536e169a31740, 0x8b0ed13925c8b4ad, 0x0080dbafe936361d}}, - {{0x8ce5aad0c9cb971f, 0x1156aaa99fd54a29, 0x41f7247015af9b78, 0x1fe8cca8420f49aa}}, - {{0x72a1848f3c0cc82a, 0x38c560c2877c9e54, 0x5004e228ce554140, 0x042418a103429d71}}}, -{{{0x899dea51abf3ff5f, 0x9b93a8672fc2d8ba, 0x2c38cb97be6ebd5c, 0x114d578497263b5d}}, - {{0x58e84c6f20816247, 0x8db2b2b6e36fd793, 0x977182561d484d85, 0x0822024f8632abd7}}, - {{0xb301bb7c6b1beca3, 0x55393f6dc6eb1375, 0x910d281097b6e4eb, 0x1ad4548d9d479ea3}}}, -{{{0xcd5a7da0389a48fd, 0xb38fa4aa9a78371e, 0xc6d9761b2cdb8e6c, 0x35cf51dbc97e1443}}, - {{0xa06fe66d0fe9fed3, 0xa8733a401c587909, 0x30d14d800df98953, 0x41ce5876c7b30258}}, - {{0x59ac3bc5d670c022, 0xeae67c109b119406, 0x9798bdf0b3782fda, 0x651e3201fd074092}}}, -{{{0xd63d8483ef30c5cf, 0x4cd4b4962361cc0c, 0xee90e500a48426ac, 0x0af51d7d18c14eeb}}, - {{0xa57ba4a01efcae9e, 0x769f4beedc308a94, 0xd1f10eeb3603cb2e, 0x4099ce5e7e441278}}, - {{0x1ac98e4f8a5121e9, 0x7dae9544dbfa2fe0, 0x8320aa0dd6430df9, 0x667282652c4a2fb5}}}, -{{{0x874621f4d86bc9ab, 0xb54c7bbe56fe6fea, 0x077a24257fadc22c, 0x1ab53be419b90d39}}, - {{0xada8b6e02946db23, 0x1c0ce51a7b253ab7, 0x8448c85a66dd485b, 0x7f1fc025d0675adf}}, - {{0xd8ee1b18319ea6aa, 0x004d88083a21f0da, 0x3bd6aa1d883a4f4b, 0x4db9a3a6dfd9fd14}}}, -{{{0x8ce7b23bb99c0755, 0x35c5d6edc4f50f7a, 0x7e1e2ed2ed9b50c3, 0x36305f16e8934da1}}, - {{0xd95b00bbcbb77c68, 0xddbc846a91f17849, 0x7cf700aebe28d9b3, 0x5ce1285c85d31f3e}}, - {{0x31b6972d98b0bde8, 0x7d920706aca6de5b, 0xe67310f8908a659f, 0x50fac2a6efdf0235}}}, -{{{0xf3d3a9f35b880f5a, 0xedec050cdb03e7c2, 0xa896981ff9f0b1a2, 0x49a4ae2bac5e34a4}}, - {{0x295b1c86f6f449bc, 0x51b2e84a1f0ab4dd, 0xc001cb30aa8e551d, 0x6a28d35944f43662}}, - {{0x28bb12ee04a740e0, 0x14313bbd9bce8174, 0x72f5b5e4e8c10c40, 0x7cbfb19936adcd5b}}}, -{{{0xa311ddc26b89792d, 0x1b30b4c6da512664, 0x0ca77b4ccf150859, 0x1de443df1b009408}}, - {{0x8e793a7acc36e6e0, 0xf9fab7a37d586eed, 0x3a4f9692bae1f4e4, 0x1c14b03eff5f447e}}, - {{0x19647bd114a85291, 0x57b76cb21034d3af, 0x6329db440f9d6dfa, 0x5ef43e586a571493}}}, -{{{0xef782014385675a6, 0xa2649f30aafda9e8, 0x4cd1eb505cdfa8cb, 0x46115aba1d4dc0b3}}, - {{0xa66dcc9dc80c1ac0, 0x97a05cf41b38a436, 0xa7ebf3be95dbd7c6, 0x7da0b8f68d7e7dab}}, - {{0xd40f1953c3b5da76, 0x1dac6f7321119e9b, 0x03cc6021feb25960, 0x5a5f887e83674b4b}}}, -{{{0x8f6301cf70a13d11, 0xcfceb815350dd0c4, 0xf70297d4a4bca47e, 0x3669b656e44d1434}}, - {{0x9e9628d3a0a643b9, 0xb5c3cb00e6c32064, 0x9b5302897c2dec32, 0x43e37ae2d5d1c70c}}, - {{0x387e3f06eda6e133, 0x67301d5199a13ac0, 0xbd5ad8f836263811, 0x6a21e6cd4fd5e9be}}}, -{{{0xf1c6170a3046e65f, 0x58712a2a00d23524, 0x69dbbd3c8c82b755, 0x586bf9f1a195ff57}}, - {{0xef4129126699b2e3, 0x71d30847708d1301, 0x325432d01182b0bd, 0x45371b07001e8b36}}, - {{0xa6db088d5ef8790b, 0x5278f0dc610937e5, 0xac0349d261a16eb8, 0x0eafb03790e52179}}}, -{{{0x960555c13748042f, 0x219a41e6820baa11, 0x1c81f73873486d0c, 0x309acc675a02c661}}, - {{0x5140805e0f75ae1d, 0xec02fbe32662cc30, 0x2cebdf1eea92396d, 0x44ae3344c5435bb3}}, - {{0x9cf289b9bba543ee, 0xf3760e9d5ac97142, 0x1d82e5c64f9360aa, 0x62d5221b7f94678f}}}, -{{{0x524c299c18d0936d, 0xc86bb56c8a0c1a0c, 0xa375052edb4a8631, 0x5c0efde4bc754562}}, - {{0x7585d4263af77a3c, 0xdfae7b11fee9144d, 0xa506708059f7193d, 0x14f29a5383922037}}, - {{0xdf717edc25b2d7f5, 0x21f970db99b53040, 0xda9234b7c3ed4c62, 0x5e72365c7bee093e}}}, -{{{0x575bfc074571217f, 0x3779675d0694d95b, 0x9a0a37bbf4191e33, 0x77f1104c47b4eabc}}, - {{0x7d9339062f08b33e, 0x5b9659e5df9f32be, 0xacff3dad1f9ebdfd, 0x70b20555cb7349b7}}, - {{0xbe5113c555112c4c, 0x6688423a9a881fcd, 0x446677855e503b47, 0x0e34398f4a06404a}}}, -{{{0xb67d22d93ecebde8, 0x09b3e84127822f07, 0x743fa61fb05b6d8d, 0x5e5405368a362372}}, - {{0x18930b093e4b1928, 0x7de3e10e73f3f640, 0xf43217da73395d6f, 0x6f8aded6ca379c3e}}, - {{0xe340123dfdb7b29a, 0x487b97e1a21ab291, 0xf9967d02fde6949e, 0x780de72ec8d3de97}}}, -{{{0x0ae28545089ae7bc, 0x388ddecf1c7f4d06, 0x38ac15510a4811b8, 0x0eb28bf671928ce4}}, - {{0x671feaf300f42772, 0x8f72eb2a2a8c41aa, 0x29a17fd797373292, 0x1defc6ad32b587a6}}, - {{0xaf5bbe1aef5195a7, 0x148c1277917b15ed, 0x2991f7fb7ae5da2e, 0x467d201bf8dd2867}}}, -{{{0x7906ee72f7bd2e6b, 0x05d270d6109abf4e, 0x8d5cfe45b941a8a4, 0x44c218671c974287}}, - {{0x745f9d56296bc318, 0x993580d4d8152e65, 0xb0e5b13f5839e9ce, 0x51fc2b28d43921c0}}, - {{0x1b8fd11795e2a98c, 0x1c4e5ee12b6b6291, 0x5b30e7107424b572, 0x6e6b9de84c4f4ac6}}}, -{{{0xdff25fce4b1de151, 0xd841c0c7e11c4025, 0x2554b3c854749c87, 0x2d292459908e0df9}}, - {{0x6b7c5f10f80cb088, 0x736b54dc56e42151, 0xc2b620a5c6ef99c4, 0x5f4c802cc3a06f42}}, - {{0x9b65c8f17d0752da, 0x881ce338c77ee800, 0xc3b514f05b62f9e3, 0x66ed5dd5bec10d48}}}, -{{{0x7d38a1c20bb2089d, 0x808334e196ccd412, 0xc4a70b8c6c97d313, 0x2eacf8bc03007f20}}, - {{0xf0adf3c9cbca047d, 0x81c3b2cbf4552f6b, 0xcfda112d44735f93, 0x1f23a0c77e20048c}}, - {{0xf235467be5bc1570, 0x03d2d9020dbab38c, 0x27529aa2fcf9e09e, 0x0840bef29d34bc50}}}, -{{{0x796dfb35dc10b287, 0x27176bcd5c7ff29d, 0x7f3d43e8c7b24905, 0x0304f5a191c54276}}, - {{0xcd54e06b7f37e4eb, 0x8cc15f87f5e96cca, 0xb8248bb0d3597dce, 0x246affa06074400c}}, - {{0x37d88e68fbe45321, 0x86097548c0d75032, 0x4e9b13ef894a0d35, 0x25a83cac5753d325}}}, -{{{0x10222f48eed8165e, 0x623fc1234b8bcf3a, 0x1e145c09c221e8f0, 0x7ccfa59fca782630}}, - {{0x9f0f66293952b6e2, 0x33db5e0e0934267b, 0xff45252bd609fedc, 0x06be10f5c506e0c9}}, - {{0x1a9615a9b62a345f, 0x22050c564a52fecc, 0xa7a2788528bc0dfe, 0x5e82770a1a1ee71d}}}, -{{{0x35425183ad896a5c, 0xe8673afbe78d52f6, 0x2c66f25f92a35f64, 0x09d04f3b3b86b102}}, - {{0xe802e80a42339c74, 0x34175166a7fffae5, 0x34865d1f1c408cae, 0x2cca982c605bc5ee}}, - {{0xfd2d5d35197dbe6e, 0x207c2eea8be4ffa3, 0x2613d8db325ae918, 0x7a325d1727741d3e}}}, -{{{0xd036b9bbd16dfde2, 0xa2055757c497a829, 0x8e6cc966a7f12667, 0x4d3b1a791239c180}}, - {{0xecd27d017e2a076a, 0xd788689f1636495e, 0x52a61af0919233e5, 0x2a479df17bb1ae64}}, - {{0x9e5eee8e33db2710, 0x189854ded6c43ca5, 0xa41c22c592718138, 0x27ad5538a43a5e9b}}}, -{{{0x2746dd4b15350d61, 0xd03fcbc8ee9521b7, 0xe86e365a138672ca, 0x510e987f7e7d89e2}}, - {{0xcb5a7d638e47077c, 0x8db7536120a1c059, 0x549e1e4d8bedfdcc, 0x080153b7503b179d}}, - {{0xdda69d930a3ed3e3, 0x3d386ef1cd60a722, 0xc817ad58bdaa4ee6, 0x23be8d554fe7372a}}}, -{{{0x95fe919a74ef4fad, 0x3a827becf6a308a2, 0x964e01d309a47b01, 0x71c43c4f5ba3c797}}, - {{0xbc1ef4bd567ae7a9, 0x3f624cb2d64498bd, 0xe41064d22c1f4ec8, 0x2ef9c5a5ba384001}}, - {{0xb6fd6df6fa9e74cd, 0xf18278bce4af267a, 0x8255b3d0f1ef990e, 0x5a758ca390c5f293}}}, -{{{0xa2b72710d9462495, 0x3aa8c6d2d57d5003, 0xe3d400bfa0b487ca, 0x2dbae244b3eb72ec}}, - {{0x8ce0918b1d61dc94, 0x8ded36469a813066, 0xd4e6a829afe8aad3, 0x0a738027f639d43f}}, - {{0x980f4a2f57ffe1cc, 0x00670d0de1839843, 0x105c3f4a49fb15fd, 0x2698ca635126a69c}}}, -{{{0xe765318832b0ba78, 0x381831f7925cff8b, 0x08a81b91a0291fcc, 0x1fb43dcc49caeb07}}, - {{0x2e3d702f5e3dd90e, 0x9e3f0918e4d25386, 0x5e773ef6024da96a, 0x3c004b0c4afa3332}}, - {{0x9aa946ac06f4b82b, 0x1ca284a5a806c4f3, 0x3ed3265fc6cd4787, 0x6b43fd01cd1fd217}}}, -{{{0xc7a75d4b4697c544, 0x15fdf848df0fffbf, 0x2868b9ebaa46785a, 0x5a68d7105b52f714}}, - {{0xb5c742583e760ef3, 0x75dc52b9ee0ab990, 0xbf1427c2072b923f, 0x73420b2d6ff0d9f0}}, - {{0xaf2cf6cb9e851e06, 0x8f593913c62238c4, 0xda8ab89699fbf373, 0x3db5632fea34bc9e}}}, -{{{0xf46eee2bf75dd9d8, 0x0d17b1f6396759a5, 0x1bf2d131499e7273, 0x04321adf49d75f13}}, - {{0x2e4990b1829825d5, 0xedeaeb873e9a8991, 0xeef03d394c704af8, 0x59197ea495df2b0e}}, - {{0x04e16019e4e55aae, 0xe77b437a7e2f92e9, 0xc7ce2dc16f159aa4, 0x45eafdc1f4d70cc0}}}, -{{{0x698401858045d72b, 0x4c22faa2cf2f0651, 0x941a36656b222dc6, 0x5a5eebc80362dade}}, - {{0xb60e4624cfccb1ed, 0x59dbc292bd5c0395, 0x31a09d1ddc0481c9, 0x3f73ceea5d56d940}}, - {{0xb7a7bfd10a4e8dc6, 0xbe57007e44c9b339, 0x60c1207f1557aefa, 0x26058891266218db}}}, -{{{0x59f704a68360ff04, 0xc3d93fde7661e6f4, 0x831b2a7312873551, 0x54ad0c2e4e615d57}}, - {{0x4c818e3cc676e542, 0x5e422c9303ceccad, 0xec07cccab4129f08, 0x0dedfa10b24443b8}}, - {{0xee3b67d5b82b522a, 0x36f163469fa5c1eb, 0xa5b4d2f26ec19fd3, 0x62ecb2baa77a9408}}}, -{{{0xe5ed795261152b3d, 0x4962357d0eddd7d1, 0x7482c8d0b96b4c71, 0x2e59f919a966d8be}}, - {{0x92072836afb62874, 0x5fcd5e8579e104a5, 0x5aad01adc630a14a, 0x61913d5075663f98}}, - {{0x0dc62d361a3231da, 0xfa47583294200270, 0x02d801513f9594ce, 0x3ddbc2a131c05d5c}}}, -{{{0x3f50a50a4ffb81ef, 0xb1e035093bf420bf, 0x9baa8e1cc6aa2cd0, 0x32239861fa237a40}}, - {{0xfb735ac2004a35d1, 0x31de0f433a6607c3, 0x7b8591bfc528d599, 0x55be9a25f5bb050c}}, - {{0x0d005acd33db3dbf, 0x0111b37c80ac35e2, 0x4892d66c6f88ebeb, 0x770eadb16508fbcd}}}, -{{{0x8451f9e05e4e89dd, 0xc06302ffbc793937, 0x5d22749556a6495c, 0x09a6755ca05603fb}}, - {{0xf1d3b681a05071b9, 0x2207659a3592ff3a, 0x5f0169297881e40e, 0x16bedd0e86ba374e}}, - {{0x5ecccc4f2c2737b5, 0x43b79e0c2dccb703, 0x33e008bc4ec43df3, 0x06c1b840f07566c0}}}, -{{{0x7688a5c6a388f877, 0x02a96c14deb2b6ac, 0x64c9f3431b8c2af8, 0x3628435554a1eed6}}, - {{0x69ee9e7f9b02805c, 0xcbff828a547d1640, 0x3d93a869b2430968, 0x46b7b8cd3fe26972}}, - {{0xe9812086fe7eebe0, 0x4cba6be72f515437, 0x1d04168b516efae9, 0x5ea1391043982cb9}}}, -{{{0x49125c9cf4702ee1, 0x4520b71f8b25b32d, 0x33193026501fef7e, 0x656d8997c8d2eb2b}}, - {{0x6f2b3be4d5d3b002, 0xafec33d96a09c880, 0x035f73a4a8bcc4cc, 0x22c5b9284662198b}}, - {{0xcb58c8fe433d8939, 0x89a0cb2e6a8d7e50, 0x79ca955309fbbe5a, 0x0c626616cd7fc106}}}, -{{{0x1ffeb80a4879b61f, 0x6396726e4ada21ed, 0x33c7b093368025ba, 0x471aa0c6f3c31788}}, - {{0x8fdfc379fbf454b1, 0x45a5a970f1a4b771, 0xac921ef7bad35915, 0x42d088dca81c2192}}, - {{0x8fda0f37a0165199, 0x0adadb77c8a0e343, 0x20fbfdfcc875e820, 0x1cf2bea80c2206e7}}}, -{{{0xc2ddf1deb36202ac, 0x92a5fe09d2e27aa5, 0x7d1648f6fc09f1d3, 0x74c2cc0513bc4959}}, - {{0x982d6e1a02c0412f, 0x90fa4c83db58e8fe, 0x01c2f5bcdcb18bc0, 0x686e0c90216abc66}}, - {{0x1fadbadba54395a7, 0xb41a02a0ae0da66a, 0xbf19f598bba37c07, 0x6a12b8acde48430d}}}, -{{{0xf8daea1f39d495d9, 0x592c190e525f1dfc, 0xdb8cbd04c9991d1b, 0x11f7fda3d88f0cb7}}, - {{0x793bdd801aaeeb5f, 0x00a2a0aac1518871, 0xe8a373a31f2136b4, 0x48aab888fc91ef19}}, - {{0x041f7e925830f40e, 0x002d6ca979661c06, 0x86dc9ff92b046a2e, 0x760360928b0493d1}}}, -{{{0x21bb41c6120cf9c6, 0xeab2aa12decda59b, 0xc1a72d020aa48b34, 0x215d4d27e87d3b68}}, - {{0xb43108e5695a0b05, 0x6cb00ee8ad37a38b, 0x5edad6eea3537381, 0x3f2602d4b6dc3224}}, - {{0xc8b247b65bcaf19c, 0x49779dc3b1b2c652, 0x89a180bbd5ece2e2, 0x13f098a3cec8e039}}}, -{{{0x9adc0ff9ce5ec54b, 0x039c2a6b8c2f130d, 0x028007c7f0f89515, 0x78968314ac04b36b}}, - {{0xf3aa57a22796bb14, 0x883abab79b07da21, 0xe54be21831a0391c, 0x5ee7fb38d83205f9}}, - {{0x538dfdcb41446a8e, 0xa5acfda9434937f9, 0x46af908d263c8c78, 0x61d0633c9bca0d09}}}, -{{{0x63744935ffdb2566, 0xc5bd6b89780b68bb, 0x6f1b3280553eec03, 0x6e965fd847aed7f5}}, - {{0xada328bcf8fc73df, 0xee84695da6f037fc, 0x637fb4db38c2a909, 0x5b23ac2df8067bdc}}, - {{0x9ad2b953ee80527b, 0xe88f19aafade6d8d, 0x0e711704150e82cf, 0x79b9bbb9dd95dedc}}}, -{{{0xebb355406a3126c2, 0xd26383a868c8c393, 0x6c0c6429e5b97a82, 0x5065f158c9fd2147}}, - {{0xd1997dae8e9f7374, 0xa032a2f8cfbb0816, 0xcd6cba126d445f0a, 0x1ba811460accb834}}, - {{0x708169fb0c429954, 0xe14600acd76ecf67, 0x2eaab98a70e645ba, 0x3981f39e58a4faf2}}}, -{{{0x18fb8a7559230a93, 0x1d168f6960e6f45d, 0x3a85a94514a93cb5, 0x38dc083705acd0fd}}, - {{0xc845dfa56de66fde, 0xe152a5002c40483a, 0xe9d2e163c7b4f632, 0x30f4452edcbc1b65}}, - {{0x856d2782c5759740, 0xfa134569f99cbecc, 0x8844fc73c0ea4e71, 0x632d9a1a593f2469}}}, -{{{0xf6bb6b15b807cba6, 0x1823c7dfbc54f0d7, 0xbb1d97036e29670b, 0x0b24f48847ed4a57}}, - {{0xbf09fd11ed0c84a7, 0x63f071810d9f693a, 0x21908c2d57cf8779, 0x3a5a7df28af64ba2}}, - {{0xdcdad4be511beac7, 0xa4538075ed26ccf2, 0xe19cff9f005f9a65, 0x34fcf74475481f63}}}, -{{{0xc197e04c789767ca, 0xb8714dcb38d9467d, 0x55de888283f95fa8, 0x3d3bdc164dfa63f7}}, - {{0xa5bb1dab78cfaa98, 0x5ceda267190b72f2, 0x9309c9110a92608e, 0x0119a3042fb374b0}}, - {{0x67a2d89ce8c2177d, 0x669da5f66895d0c1, 0xf56598e5b282a2b0, 0x56c088f1ede20a73}}}, -{{{0x336d3d1110a86e17, 0xd7f388320b75b2fa, 0xf915337625072988, 0x09674c6b99108b87}}, - {{0x581b5fac24f38f02, 0xa90be9febae30cbd, 0x9a2169028acf92f0, 0x038b7ea48359038f}}, - {{0x9f4ef82199316ff8, 0x2f49d282eaa78d4f, 0x0971a5ab5aef3174, 0x6e5e31025969eb65}}}, -{{{0xb16c62f587e593fb, 0x4999eddeca5d3e71, 0xb491c1e014cc3e6d, 0x08f5114789a8dba8}}, - {{0x3304fb0e63066222, 0xfb35068987acba3f, 0xbd1924778c1061a3, 0x3058ad43d1838620}}, - {{0x323c0ffde57663d0, 0x05c3df38a22ea610, 0xbdc78abdac994f9a, 0x26549fa4efe3dc99}}}, -{{{0x738b38d787ce8f89, 0xb62658e24179a88d, 0x30738c9cf151316d, 0x49128c7f727275c9}}, - {{0x04dbbc17f75396b9, 0x69e6a2d7d2f86746, 0xc6409d99f53eabc6, 0x606175f6332e25d2}}, - {{0x4021370ef540e7dd, 0x0910d6f5a1f1d0a5, 0x4634aacd5b06b807, 0x6a39e6356944f235}}}, -{{{0x96cd5640df90f3e7, 0x6c3a760edbfa25ea, 0x24f3ef0959e33cc4, 0x42889e7e530d2e58}}, - {{0x1da1965774049e9d, 0xfbcd6ea198fe352b, 0xb1cbcd50cc5236a6, 0x1f5ec83d3f9846e2}}, - {{0x8efb23c3328ccb75, 0xaf42a207dd876ee9, 0x20fbdadc5dfae796, 0x241e246b06bf9f51}}}, -{{{0x29e68e57ad6e98f6, 0x4c9260c80b462065, 0x3f00862ea51ebb4b, 0x5bc2c77fb38d9097}}, - {{0x7eaafc9a6280bbb8, 0x22a70f12f403d809, 0x31ce40bb1bfc8d20, 0x2bc65635e8bd53ee}}, - {{0xe8d5dc9fa96bad93, 0xe58fb17dde1947dc, 0x681532ea65185fa3, 0x1fdd6c3b034a7830}}}, -{{{0x0a64e28c55dc18fe, 0xe3df9e993399ebdd, 0x79ac432370e2e652, 0x35ff7fc33ae4cc0e}}, - {{0x9c13a6a52dd8f7a9, 0x2dbb1f8c3efdcabf, 0x961e32405e08f7b5, 0x48c8a121bbe6c9e5}}, - {{0xfc415a7c59646445, 0xd224b2d7c128b615, 0x6035c9c905fbb912, 0x42d7a91274429fab}}}, -{{{0x4e6213e3eaf72ed3, 0x6794981a43acd4e7, 0xff547cde6eb508cb, 0x6fed19dd10fcb532}}, - {{0xa9a48947933da5bc, 0x4a58920ec2e979ec, 0x96d8800013e5ac4c, 0x453692d74b48b147}}, - {{0xdd775d99a8559c6f, 0xf42a2140df003e24, 0x5223e229da928a66, 0x063f46ba6d38f22c}}}, -{{{0xd2d242895f536694, 0xca33a2c542939b2c, 0x986fada6c7ddb95c, 0x5a152c042f712d5d}}, - {{0x39843cb737346921, 0xa747fb0738c89447, 0xcb8d8031a245307e, 0x67810f8e6d82f068}}, - {{0x3eeb8fbcd2287db4, 0x72c7d3a301a03e93, 0x5473e88cbd98265a, 0x7324aa515921b403}}}, -{{{0x857942f46c3cbe8e, 0xa1d364b14730c046, 0x1c8ed914d23c41bf, 0x0838e161eef6d5d2}}, - {{0xad23f6dae82354cb, 0x6962502ab6571a6d, 0x9b651636e38e37d1, 0x5cac5005d1a3312f}}, - {{0x8cc154cce9e39904, 0x5b3a040b84de6846, 0xc4d8a61cb1be5d6e, 0x40fb897bd8861f02}}}, -{{{0x84c5aa9062de37a1, 0x421da5000d1d96e1, 0x788286306a9242d9, 0x3c5e464a690d10da}}, - {{0xe57ed8475ab10761, 0x71435e206fd13746, 0x342f824ecd025632, 0x4b16281ea8791e7b}}, - {{0xd1c101d50b813381, 0xdee60f1176ee6828, 0x0cb68893383f6409, 0x6183c565f6ff484a}}}, -{{{0x741d5a461e6bf9d6, 0x2305b3fc7777a581, 0xd45574a26474d3d9, 0x1926e1dc6401e0ff}}, - {{0xdb468549af3f666e, 0xd77fcf04f14a0ea5, 0x3df23ff7a4ba0c47, 0x3a10dfe132ce3c85}}, - {{0xe07f4e8aea17cea0, 0x2fd515463a1fc1fd, 0x175322fd31f2c0f1, 0x1fa1d01d861e5d15}}}, -{{{0xcc8055947d599832, 0x1e4656da37f15520, 0x99f6f7744e059320, 0x773563bc6a75cf33}}, - {{0x38dcac00d1df94ab, 0x2e712bddd1080de9, 0x7f13e93efdd5e262, 0x73fced18ee9a01e5}}, - {{0x06b1e90863139cb3, 0xa493da67c5a03ecd, 0x8d77cec8ad638932, 0x1f426b701b864f44}}}, -{{{0xefc9264c41911c01, 0xf1a3b7b817a22c25, 0x5875da6bf30f1447, 0x4e1af5271d31b090}}, - {{0xf17e35c891a12552, 0xb76b8153575e9c76, 0xfa83406f0d9b723e, 0x0b76bb1b3fa7e438}}, - {{0x08b8c1f97f92939b, 0xbe6771cbd444ab6e, 0x22e5646399bb8017, 0x7b6dd61eb772a955}}}, -{{{0xb7adc1e850f33d92, 0x7998fa4f608cd5cf, 0xad962dbd8dfc5bdb, 0x703e9bceaf1d2f4f}}, - {{0x5730abf9ab01d2c7, 0x16fb76dc40143b18, 0x866cbe65a0cbb281, 0x53fa9b659bff6afe}}, - {{0x6c14c8e994885455, 0x843a5d6665aed4e5, 0x181bb73ebcd65af1, 0x398d93e5c4c61f50}}}, -{{{0x1c4bd16733e248f3, 0xbd9e128715bf0a5f, 0xd43f8cf0a10b0376, 0x53b09b5ddf191b13}}, - {{0xc3877c60d2e7e3f2, 0x3b34aaa030828bb1, 0x283e26e7739ef138, 0x699c9c9002c30577}}, - {{0xf306a7235946f1cc, 0x921718b5cce5d97d, 0x28cdd24781b4e975, 0x51caf30c6fcdd907}}}, -{{{0xa60ba7427674e00a, 0x630e8570a17a7bf3, 0x3758563dcf3324cc, 0x5504aa292383fdaa}}, - {{0x737af99a18ac54c7, 0x903378dcc51cb30f, 0x2b89bc334ce10cc7, 0x12ae29c189f8e99a}}, - {{0xa99ec0cb1f0d01cf, 0x0dd1efcc3a34f7ae, 0x55ca7521d09c4e22, 0x5fd14fe958eba5ea}}}, -{{{0xb5dc2ddf2845ab2c, 0x069491b10a7fe993, 0x4daaf3d64002e346, 0x093ff26e586474d1}}, - {{0x3c42fe5ebf93cb8e, 0xbedfa85136d4565f, 0xe0f0859e884220e8, 0x7dd73f960725d128}}, - {{0xb10d24fe68059829, 0x75730672dbaf23e5, 0x1367253ab457ac29, 0x2f59bcbc86b470a4}}}, -{{{0x83847d429917135f, 0xad1b911f567d03d7, 0x7e7748d9be77aad1, 0x5458b42e2e51af4a}}, - {{0x7041d560b691c301, 0x85201b3fadd7e71e, 0x16c2e16311335585, 0x2aa55e3d010828b1}}, - {{0xed5192e60c07444f, 0x42c54e2d74421d10, 0x352b4c82fdb5c864, 0x13e9004a8a768664}}}, -{{{0xcbb5b5556c032bff, 0xdf7191b729297a3a, 0xc1ff7326aded81bb, 0x71ade8bb68be03f5}}, - {{0x1e6284c5806b467c, 0xc5f6997be75d607b, 0x8b67d958b378d262, 0x3d88d66a81cd8b70}}, - {{0x8b767a93204ed789, 0x762fcacb9fa0ae2a, 0x771febcc6dce4887, 0x343062158ff05fb3}}}, -{{{0xe05da1a7e1f5bf49, 0x26457d6dd4736092, 0x77dcb07773cc32f6, 0x0a5d94969cdd5fcd}}, - {{0xfce219072a7b31b4, 0x4d7adc75aa578016, 0x0ec276a687479324, 0x6d6d9d5d1fda4beb}}, - {{0x22b1a58ae9b08183, 0xfd95d071c15c388b, 0xa9812376850a0517, 0x33384cbabb7f335e}}}, -{{{0x3c6fa2680ca2c7b5, 0x1b5082046fb64fda, 0xeb53349c5431d6de, 0x5278b38f6b879c89}}, - {{0x33bc627a26218b8d, 0xea80b21fc7a80c61, 0x9458b12b173e9ee6, 0x076247be0e2f3059}}, - {{0x52e105f61416375a, 0xec97af3685abeba4, 0x26e6b50623a67c36, 0x5cf0e856f3d4fb01}}}, -{{{0xf6c968731ae8cab4, 0x5e20741ecb4f92c5, 0x2da53be58ccdbc3e, 0x2dddfea269970df7}}, - {{0xbeaece313db342a8, 0xcba3635b842db7ee, 0xe88c6620817f13ef, 0x1b9438aa4e76d5c6}}, - {{0x8a50777e166f031a, 0x067b39f10fb7a328, 0x1925c9a6010fbd76, 0x6df9b575cc740905}}}, -{{{0x42c1192927f6bdcf, 0x8f91917a403d61ca, 0xdc1c5a668b9e1f61, 0x1596047804ec0f8d}}, - {{0xecdfc35b48cade41, 0x6a88471fb2328270, 0x740a4a2440a01b6a, 0x471e5796003b5f29}}, - {{0xda96bbb3aced37ac, 0x7a2423b5e9208cea, 0x24cc5c3038aebae2, 0x50c356afdc5dae2f}}}, -{{{0x09dcbf4341c30318, 0xeeba061183181dce, 0xc179c0cedc1e29a1, 0x1dbf7b89073f35b0}}, - {{0xcfed9cdf1b31b964, 0xf486a9858ca51af3, 0x14897265ea8c1f84, 0x784a53dd932acc00}}, - {{0x2d99f9df14fc4920, 0x76ccb60cc4499fe5, 0xa4132cbbe5cf0003, 0x3f93d82354f000ea}}}, -{{{0x8183e7689e04ce85, 0x678fb71e04465341, 0xad92058f6688edac, 0x5da350d3532b099a}}, - {{0xeaac12d179e14978, 0xff923ff3bbebff5e, 0x4af663e40663ce27, 0x0fd381a811a5f5ff}}, - {{0xf256aceca436df54, 0x108b6168ae69d6e8, 0x20d986cb6b5d036c, 0x655957b9fee2af50}}}, -{{{0xaea8b07fa902030f, 0xf88c766af463d143, 0x15b083663c787a60, 0x08eab1148267a4a8}}, - {{0xbdc1409bd002d0ac, 0x66660245b5ccd9a6, 0x82317dc4fade85ec, 0x02fe934b6ad7df0d}}, - {{0xef5cf100cfb7ea74, 0x22897633a1cb42ac, 0xd4ce0c54cef285e2, 0x30408c048a146a55}}}, -{{{0x739d8845832fcedb, 0xfa38d6c9ae6bf863, 0x32bc0dcab74ffef7, 0x73937e8814bce45e}}, - {{0xbb2e00c9193b877f, 0xece3a890e0dc506b, 0xecf3b7c036de649f, 0x5f46040898de9e1a}}, - {{0xb9037116297bf48d, 0xa9d13b22d4f06834, 0xe19715574696bdc6, 0x2cf8a4e891d5e835}}}, -{{{0x6d93fd8707110f67, 0xdd4c09d37c38b549, 0x7cb16a4cc2736a86, 0x2049bd6e58252a09}}, - {{0x2cb5487e17d06ba2, 0x24d2381c3950196b, 0xd7659c8185978a30, 0x7a6f7f2891d6a4f6}}, - {{0x7d09fd8d6a9aef49, 0xf0ee60be5b3db90b, 0x4c21b52c519ebfd4, 0x6011aadfc545941d}}}, -{{{0x5f67926dcf95f83c, 0x7c7e856171289071, 0xd6a1e7f3998f7a5b, 0x6fc5cc1b0b62f9e0}}, - {{0x63ded0c802cbf890, 0xfbd098ca0dff6aaa, 0x624d0afdb9b6ed99, 0x69ce18b779340b1e}}, - {{0xd1ef5528b29879cb, 0xdd1aae3cd47e9092, 0x127e0442189f2352, 0x15596b3ae57101f1}}}, -{{{0x462739d23f9179a2, 0xff83123197d6ddcf, 0x1307deb553f2148a, 0x0d2237687b5f4dda}}, - {{0x09ff31167e5124ca, 0x0be4158bd9c745df, 0x292b7d227ef556e5, 0x3aa4e241afb6d138}}, - {{0x2cc138bf2a3305f5, 0x48583f8fa2e926c3, 0x083ab1a25549d2eb, 0x32fcaa6e4687a36c}}}, -{{{0x7bc56e8dc57d9af5, 0x3e0bd2ed9df0bdf2, 0xaac014de22efe4a3, 0x4627e9cefebd6a5c}}, - {{0x3207a4732787ccdf, 0x17e31908f213e3f8, 0xd5b2ecd7f60d964e, 0x746f6336c2600be9}}, - {{0x3f4af345ab6c971c, 0xe288eb729943731f, 0x33596a8a0344186d, 0x7b4917007ed66293}}}, -{{{0x2d85fb5cab84b064, 0x497810d289f3bc14, 0x476adc447b15ce0c, 0x122ba376f844fd7b}}, - {{0x54341b28dd53a2dd, 0xaa17905bdf42fc3f, 0x0ff592d94dd2f8f4, 0x1d03620fe08cd37d}}, - {{0xc20232cda2b4e554, 0x9ed0fd42115d187f, 0x2eabb4be7dd479d9, 0x02c70bf52b68ec4c}}}, -{{{0xa287ec4b5d0b2fbb, 0x415c5790074882ca, 0xe044a61ec1d0815c, 0x26334f0a409ef5e0}}, - {{0xace532bf458d72e1, 0x5be768e07cb73cb5, 0x56cf7d94ee8bbde7, 0x6b0697e3feb43a03}}, - {{0xb6c8f04adf62a3c0, 0x3ef000ef076da45d, 0x9c9cb95849f0d2a9, 0x1cc37f43441b2fae}}}, -{{{0x508f565a5cc7324f, 0xd061c4c0e506a922, 0xfb18abdb5c45ac19, 0x6c6809c10380314a}}, - {{0xd76656f1c9ceaeb9, 0x1c5b15f818e5656a, 0x26e72832844c2334, 0x3a346f772f196838}}, - {{0xd2d55112e2da6ac8, 0xe9bd0331b1e851ed, 0x960746dd8ec67262, 0x05911b9f6ef7c5d0}}}, -{{{0xe9dcd756b637ff2d, 0xec4c348fc987f0c4, 0xced59285f3fbc7b7, 0x3305354793e1ea87}}, - {{0x01c18980c5fe9f94, 0xcd656769716fd5c8, 0x816045c3d195a086, 0x6e2b7f3266cc7982}}, - {{0xcc802468f7c3568f, 0x9de9ba8219974cb3, 0xabb7229cb5b81360, 0x44e2017a6fbeba62}}}, -{{{0xc4c2a74354dab774, 0x8e5d4c3c4eaf031a, 0xb76c23d242838f17, 0x749a098f68dce4ea}}, - {{0x87f82cf3b6ca6ecd, 0x580f893e18f4a0c2, 0x058930072604e557, 0x6cab6ac256d19c1d}}, - {{0xdcdfe0a02cc1de60, 0x032665ff51c5575b, 0x2c0c32f1073abeeb, 0x6a882014cd7b8606}}}, -{{{0xa52a92fea4747fb5, 0xdc12a4491fa5ab89, 0xd82da94bb847a4ce, 0x4d77edce9512cc4e}}, - {{0xd111d17caf4feb6e, 0x050bba42b33aa4a3, 0x17514c3ceeb46c30, 0x54bedb8b1bc27d75}}, - {{0x77c8e14577e2189c, 0xa3e46f6aff99c445, 0x3144dfc86d335343, 0x3a96559e7c4216a9}}}, -{{{0x12550d37f42ad2ee, 0x8b78e00498a1fbf5, 0x5d53078233894cb2, 0x02c84e4e3e498d0c}}, - {{0x4493896880baaa52, 0x4c98afc4f285940e, 0xef4aa79ba45448b6, 0x5278c510a57aae7f}}, - {{0xa54dd074294c0b94, 0xf55d46b8df18ffb6, 0xf06fecc58dae8366, 0x588657668190d165}}}, -{{{0xd47712311aef7117, 0x50343101229e92c7, 0x7a95e1849d159b97, 0x2449959b8b5d29c9}}, - {{0xbf5834f03de25cc3, 0xb887c8aed6815496, 0x5105221a9481e892, 0x6760ed19f7723f93}}, - {{0x669ba3b7ac35e160, 0x2eccf73fba842056, 0x1aec1f17c0804f07, 0x0d96bc031856f4e7}}}, -{{{0x3318be7775c52d82, 0x4cb764b554d0aab9, 0xabcf3d27cc773d91, 0x3bf4d1848123288a}}, - {{0xb1d534b0cc7505e1, 0x32cd003416c35288, 0xcb36a5800762c29d, 0x5bfe69b9237a0bf8}}, - {{0x183eab7e78a151ab, 0xbbe990c999093763, 0xff717d6e4ac7e335, 0x4c5cddb325f39f88}}}, -{{{0xc0f6b74d6190a6eb, 0x20ea81a42db8f4e4, 0xa8bd6f7d97315760, 0x33b1d60262ac7c21}}, - {{0x57750967e7a9f902, 0x2c37fdfc4f5b467e, 0xb261663a3177ba46, 0x3a375e78dc2d532b}}, - {{0x8141e72f2d4dddea, 0xe6eafe9862c607c8, 0x23c28458573cafd0, 0x46b9476f4ff97346}}}, -{{{0x0c1ffea44f901e5c, 0x2b0b6fb72184b782, 0xe587ff910114db88, 0x37130f364785a142}}, - {{0x1215505c0d58359f, 0x2a2013c7fc28c46b, 0x24a0a1af89ea664e, 0x4400b638a1130e1f}}, - {{0x3a01b76496ed19c3, 0x31e00ab0ed327230, 0x520a885783ca15b1, 0x06aab9875accbec7}}}, -{{{0xc1339983f5df0ebb, 0xc0f3758f512c4cac, 0x2cf1130a0bb398e1, 0x6b3cecf9aa270c62}}, - {{0x5349acf3512eeaef, 0x20c141d31cc1cb49, 0x24180c07a99a688d, 0x555ef9d1c64b2d17}}, - {{0x36a770ba3b73bd08, 0x624aef08a3afbf0c, 0x5737ff98b40946f2, 0x675f4de13381749d}}}, -{{{0x0e2c52036b1782fc, 0x64816c816cad83b4, 0xd0dcbdd96964073e, 0x13d99df70164c520}}, - {{0xa12ff6d93bdab31d, 0x0725d80f9d652dfe, 0x019c4ff39abe9487, 0x60f450b882cd3c43}}, - {{0x014b5ec321e5c0ca, 0x4fcb69c9d719bfa2, 0x4e5f1c18750023a0, 0x1c06de9e55edac80}}}, -{{{0x990f7ad6a33ec4e2, 0x6608f938be2ee08e, 0x9ca143c563284515, 0x4cf38a1fec2db60d}}, - {{0xffd52b40ff6d69aa, 0x34530b18dc4049bb, 0x5e4a5c2fa34d9897, 0x78096f8e7d32ba2d}}, - {{0xa0aaaa650dfa5ce7, 0xf9c49e2a48b5478c, 0x4f09cc7d7003725b, 0x373cad3a26091abe}}}, -{{{0xb294634d82c9f57c, 0x1fcbfde124934536, 0x9e9c4db3418cdb5a, 0x0040f3d9454419fc}}, - {{0xf1bea8fb89ddbbad, 0x3bcb2cbc61aeaecb, 0x8f58a7bb1f9b8d9d, 0x21547eda5112a686}}, - {{0xdefde939fd5986d3, 0xf4272c89510a380c, 0xb72ba407bb3119b9, 0x63550a334a254df4}}}, -{{{0x6507d6edb569cf37, 0x178429b00ca52ee1, 0xea7c0090eb6bd65d, 0x3eea62c7daf78f51}}, - {{0x9bba584572547b49, 0xf305c6fae2c408e0, 0x60e8fa69c734f18d, 0x39a92bafaa7d767a}}, - {{0x9d24c713e693274e, 0x5f63857768dbd375, 0x70525560eb8ab39a, 0x68436a0665c9c4cd}}}, -{{{0xbc0235e8202f3f27, 0xc75c00e264f975b0, 0x91a4e9d5a38c2416, 0x17b6e7f68ab789f9}}, - {{0x1e56d317e820107c, 0xc5266844840ae965, 0xc1e0a1c6320ffc7a, 0x5373669c91611472}}, - {{0x5d2814ab9a0e5257, 0x908f2084c9cab3fc, 0xafcaf5885b2d1eca, 0x1cb4b5a678f87d11}}}, -{{{0xb664c06b394afc6c, 0x0c88de2498da5fb1, 0x4f8d03164bcad834, 0x330bca78de7434a2}}, - {{0x6b74aa62a2a007e7, 0xf311e0b0f071c7b1, 0x5707e438000be223, 0x2dc0fd2d82ef6eac}}, - {{0x982eff841119744e, 0xf9695e962b074724, 0xc58ac14fbfc953fb, 0x3c31be1b369f1cf5}}}, -{{{0xb0f4864d08948aee, 0x07dc19ee91ba1c6f, 0x7975cdaea6aca158, 0x330b61134262d4bb}}, - {{0xc168bc93f9cb4272, 0xaeb8711fc7cedb98, 0x7f0e52aa34ac8d7a, 0x41cec1097e7d55bb}}, - {{0xf79619d7a26d808a, 0xbb1fd49e1d9e156d, 0x73d7c36cdba1df27, 0x26b44cd91f28777d}}}, -{{{0x300a9035393aa6d8, 0x2b501131a12bb1cd, 0x7b1ff677f093c222, 0x4309c1f8cab82bad}}, - {{0xaf44842db0285f37, 0x8753189047efc8df, 0x9574e091f820979a, 0x0e378d6069615579}}, - {{0xd9fa917183075a55, 0x4bdb5ad26b009fdc, 0x7829ad2cd63def0e, 0x078fc54975fd3877}}}, -{{{0x87dfbd1428878f2d, 0x134636dd1e9421a1, 0x4f17c951257341a3, 0x5df98d4bad296cb8}}, - {{0xe2004b5bb833a98a, 0x44775dec2d4c3330, 0x3aa244067eace913, 0x272630e3d58e00a9}}, - {{0xf3678fd0ecc90b54, 0xf001459b12043599, 0x26725fbc3758b89b, 0x4325e4aa73a719ae}}}, -{{{0x657dc6ef433c3493, 0x65375e9f80dbf8c3, 0x47fd2d465b372dae, 0x4966ab79796e7947}}, - {{0xed24629acf69f59d, 0x2a4a1ccedd5abbf4, 0x3535ca1f56b2d67b, 0x5d8c68d043b1b42d}}, - {{0xee332d4de3b42b0a, 0xd84e5a2b16a4601c, 0x78243877078ba3e4, 0x77ed1eb4184ee437}}}, -{{{0xbfd4e13f201839a0, 0xaeefffe23e3df161, 0xb65b04f06b5d1fe3, 0x52e085fb2b62fbc0}}, - {{0x185d43f89e92ed1a, 0xb04a1eeafe4719c6, 0x499fbe88a6f03f4f, 0x5d8b0d2f3c859bdd}}, - {{0x124079eaa54cf2ba, 0xd72465eb001b26e7, 0x6843bcfdc97af7fd, 0x0524b42b55eacd02}}}, -{{{0xfd0d5dbee45447b0, 0x6cec351a092005ee, 0x99a47844567579cb, 0x59d242a216e7fa45}}, - {{0xbc18dcad9b829eac, 0x23ae7d28b5f579d0, 0xc346122a69384233, 0x1a6110b2e7d4ac89}}, - {{0x4f833f6ae66997ac, 0x6849762a361839a4, 0x6985dec1970ab525, 0x53045e89dcb1f546}}}, -{{{0xcb8bb346d75353db, 0xfcfcb24bae511e22, 0xcba48d40d50ae6ef, 0x26e3bae5f4f7cb5d}}, - {{0x84da3cde8d45fe12, 0xbd42c218e444e2d2, 0xa85196781f7e3598, 0x7642c93f5616e2b2}}, - {{0x2323daa74595f8e4, 0xde688c8b857abeb4, 0x3fc48e961c59326e, 0x0b2e73ca15c9b8ba}}}, -{{{0xd6bb4428c17f5026, 0x9eb27223fb5a9ca7, 0xe37ba5031919c644, 0x21ce380db59a6602}}, - {{0x0e3fbfaf79c03a55, 0x3077af054cbb5acf, 0xd5c55245db3de39f, 0x015e68c1476a4af7}}, - {{0xc1d5285220066a38, 0x95603e523570aef3, 0x832659a7226b8a4d, 0x5dd689091f8eedc9}}}, -{{{0xcbac84debfd3c856, 0x1624c348b35ff244, 0xb7f88dca5d9cad07, 0x3b0e574da2c2ebe8}}, - {{0x1d022591a5313084, 0xca2d4aaed6270872, 0x86a12b852f0bfd20, 0x56e6c439ad7da748}}, - {{0xc704ff4942bdbae6, 0x5e21ade2b2de1f79, 0xe95db3f35652fad8, 0x0822b5378f08ebc1}}}, -{{{0x51f048478f387475, 0xb25dbcf49cbecb3c, 0x9aab1244d99f2055, 0x2c709e6c1c10a5d6}}, - {{0xe1b7f29362730383, 0x4b5279ffebca8a2c, 0xdafc778abfd41314, 0x7deb10149c72610f}}, - {{0xcb62af6a8766ee7a, 0x66cbec045553cd0e, 0x588001380f0be4b5, 0x08e68e9ff62ce2ea}}}, -{{{0x34ad500a4bc130ad, 0x8d38db493d0bd49c, 0xa25c3d98500a89be, 0x2f1f3f87eeba3b09}}, - {{0x2f2d09d50ab8f2f9, 0xacb9218dc55923df, 0x4a8f342673766cb9, 0x4cb13bd738f719f5}}, - {{0xf7848c75e515b64a, 0xa59501badb4a9038, 0xc20d313f3f751b50, 0x19a1e353c0ae2ee8}}}, -{{{0x7d1c7560bafa05c3, 0xb3e1a0a0c6e55e61, 0xe3529718c0d66473, 0x41546b11c20c3486}}, - {{0xb42172cdd596bdbd, 0x93e0454398eefc40, 0x9fb15347b44109b5, 0x736bd3990266ae34}}, - {{0x85532d509334b3b4, 0x46fd114b60816573, 0xcc5f5f30425c8375, 0x412295a2b87fab5c}}}, -{{{0x19c99b88f57ed6e9, 0x5393cb266df8c825, 0x5cee3213b30ad273, 0x14e153ebb52d2e34}}, - {{0x2e655261e293eac6, 0x845a92032133acdb, 0x460975cb7900996b, 0x0760bb8d195add80}}, - {{0x413e1a17cde6818a, 0x57156da9ed69a084, 0x2cbf268f46caccb1, 0x6b34be9bc33ac5f2}}}, -{{{0xf3df2f643a78c0b2, 0x4c3e971ef22e027c, 0xec7d1c5e49c1b5a3, 0x2012c18f0922dd2d}}, - {{0x11fc69656571f2d3, 0xc6c9e845530e737a, 0xe33ae7a2d4fe5035, 0x01b9c7b62e6dd30b}}, - {{0x880b55e55ac89d29, 0x1483241f45a0a763, 0x3d36efdfc2e76c1f, 0x08af5b784e4bade8}}}, -{{{0x283499dc881f2533, 0x9d0525da779323b6, 0x897addfb673441f4, 0x32b79d71163a168d}}, - {{0xe27314d289cc2c4b, 0x4be4bd11a287178d, 0x18d528d6fa3364ce, 0x6423c1d5afd9826e}}, - {{0xcc85f8d9edfcb36a, 0x22bcc28f3746e5f9, 0xe49de338f9e5d3cd, 0x480a5efbc13e2dcc}}}, -{{{0x0b51e70b01622071, 0x06b505cf8b1dafc5, 0x2c6bb061ef5aabcd, 0x47aa27600cb7bf31}}, - {{0xb6614ce442ce221f, 0x6e199dcc4c053928, 0x663fb4a4dc1cbe03, 0x24b31d47691c8e06}}, - {{0x2a541eedc015f8c3, 0x11a4fe7e7c693f7c, 0xf0af66134ea278d6, 0x545b585d14dda094}}}, -{{{0x67bf275ea0d43a0f, 0xade68e34089beebe, 0x4289134cd479e72e, 0x0f62f9c332ba5454}}, - {{0x6204e4d0e3b321e1, 0x3baa637a28ff1e95, 0x0b0ccffd5b99bd9e, 0x4d22dc3e64c8d071}}, - {{0xfcb46589d63b5f39, 0x5cae6a3f57cbcf61, 0xfebac2d2953afa05, 0x1c0fa01a36371436}}}, -{{{0xe7547449bc7cd692, 0x0f9abeaae6f73ddf, 0x4af01ca700837e29, 0x63ab1b5d3f1bc183}}, - {{0xc11ee5e854c53fae, 0x6a0b06c12b4f3ff4, 0x33540f80e0b67a72, 0x15f18fc3cd07e3ef}}, - {{0x32750763b028f48c, 0x06020740556a065f, 0xd53bd812c3495b58, 0x08706c9b865f508d}}}, -{{{0xf37ca2ab3d343dff, 0x1a8c6a2d80abc617, 0x8e49e035d4ccffca, 0x48b46beebaa1d1b9}}, - {{0xcc991b4138b41246, 0x243b9c526f9ac26b, 0xb9ef494db7cbabbd, 0x5fba433dd082ed00}}, - {{0x9c49e355c9941ad0, 0xb9734ade74498f84, 0x41c3fed066663e5c, 0x0ecfedf8e8e710b3}}}, -{{{0x76430f9f9cd470d9, 0xb62acc9ba42f6008, 0x1898297c59adad5e, 0x7789dd2db78c5080}}, - {{0x744f7463e9403762, 0xf79a8dee8dfcc9c9, 0x163a649655e4cde3, 0x3b61788db284f435}}, - {{0xb22228190d6ef6b2, 0xa94a66b246ce4bfa, 0x46c1a77a4f0b6cc7, 0x4236ccffeb7338cf}}}, -{{{0x8497404d0d55e274, 0x6c6663d9c4ad2b53, 0xec2fb0d9ada95734, 0x2617e120cdb8f73c}}, - {{0x3bd82dbfda777df6, 0x71b177cc0b98369e, 0x1d0e8463850c3699, 0x5a71945b48e2d1f1}}, - {{0x6f203dd5405b4b42, 0x327ec60410b24509, 0x9c347230ac2a8846, 0x77de29fc11ffeb6a}}}, -{{{0xb0ac57c983b778a8, 0x53cdcca9d7fe912c, 0x61c2b854ff1f59dc, 0x3a1a2cf0f0de7dac}}, - {{0x835e138fecced2ca, 0x8c9eaf13ea963b9a, 0xc95fbfc0b2160ea6, 0x575e66f3ad877892}}, - {{0x99803a27c88fcb3a, 0x345a6789275ec0b0, 0x459789d0ff6c2be5, 0x62f882651e70a8b2}}}, -{{{0x085ae2c759ff1be4, 0x149145c93b0e40b7, 0xc467e7fa7ff27379, 0x4eeecf0ad5c73a95}}, - {{0x6d822986698a19e0, 0xdc9821e174d78a71, 0x41a85f31f6cb1f47, 0x352721c2bcda9c51}}, - {{0x48329952213fc985, 0x1087cf0d368a1746, 0x8e5261b166c15aa5, 0x2d5b2d842ed24c21}}}, -{{{0x02cfebd9ebd3ded1, 0xd45b217739021974, 0x7576f813fe30a1b7, 0x5691b6f9a34ef6c2}}, - {{0x5eb7d13d196ac533, 0x377234ecdb80be2b, 0xe144cffc7cf5ae24, 0x5226bcf9c441acec}}, - {{0x79ee6c7223e5b547, 0x6f5f50768330d679, 0xed73e1e96d8adce9, 0x27c3da1e1d8ccc03}}}, -{{{0x7eb9efb23fe24c74, 0x3e50f49f1651be01, 0x3ea732dc21858dea, 0x17377bd75bb810f9}}, - {{0x28302e71630ef9f6, 0xc2d4a2032b64cee0, 0x090820304b6292be, 0x5fca747aa82adf18}}, - {{0x232a03c35c258ea5, 0x86f23a2c6bcb0cf1, 0x3dad8d0d2e442166, 0x04a8933cab76862b}}}, -{{{0xd2c604b622943dff, 0xbc8cbece44cfb3a0, 0x5d254ff397808678, 0x0fa3614f3b1ca6bf}}, - {{0x69082b0e8c936a50, 0xf9c9a035c1dac5b6, 0x6fb73e54c4dfb634, 0x4005419b1d2bc140}}, - {{0xa003febdb9be82f0, 0x2089c1af3a44ac90, 0xf8499f911954fa8e, 0x1fba218aef40ab42}}}, -{{{0xab549448fac8f53e, 0x81f6e89a7ba63741, 0x74fd6c7d6c2b5e01, 0x392e3acaa8c86e42}}, - {{0x4f3e57043e7b0194, 0xa81d3eee08daaf7f, 0xc839c6ab99dcdef1, 0x6c535d13ff7761d5}}, - {{0x4cbd34e93e8a35af, 0x2e0781445887e816, 0x19319c76f29ab0ab, 0x25e17fe4d50ac13b}}}, -{{{0x0a289bd71e04f676, 0x208e1c52d6420f95, 0x5186d8b034691fab, 0x255751442a9fb351}}, - {{0x915f7ff576f121a7, 0xc34a32272fcd87e3, 0xccba2fde4d1be526, 0x6bba828f8969899b}}, - {{0xe2d1bc6690fe3901, 0x4cb54a18a0997ad5, 0x971d6914af8460d4, 0x559d504f7f6b7be4}}}, -{{{0xa7738378b3eb54d5, 0x1d69d366a5553c7c, 0x0a26cf62f92800ba, 0x01ab12d5807e3217}}, - {{0x9c4891e7f6d266fd, 0x0744a19b0307781b, 0x88388f1d6061e23b, 0x123ea6a3354bd50e}}, - {{0x118d189041e32d96, 0xb9ede3c2d8315848, 0x1eab4271d83245d9, 0x4a3961e2c918a154}}}, -{{{0x71dc3be0f8e6bba0, 0xd6cef8347effe30a, 0xa992425fe13a476a, 0x2cd6bce3fb1db763}}, - {{0x0327d644f3233f1e, 0x499a260e34fcf016, 0x83b5a716f2dab979, 0x68aceead9bd4111f}}, - {{0x38b4c90ef3d7c210, 0x308e6e24b7ad040c, 0x3860d9f1b7e73e23, 0x595760d5b508f597}}}, -{{{0x6129bfe104aa6397, 0x8f960008a4a7fccb, 0x3f8bc0897d909458, 0x709fa43edcb291a9}}, - {{0x882acbebfd022790, 0x89af3305c4115760, 0x65f492e37d3473f4, 0x2cb2c5df54515a2b}}, - {{0xeb0a5d8c63fd2aca, 0xd22bc1662e694eff, 0x2723f36ef8cbb03a, 0x70f029ecf0c8131f}}}, -{{{0x461307b32eed3e33, 0xae042f33a45581e7, 0xc94449d3195f0366, 0x0b7d5d8a6c314858}}, - {{0x2a6aafaa5e10b0b9, 0x78f0a370ef041aa9, 0x773efb77aa3ad61f, 0x44eca5a2a74bd9e1}}, - {{0x25d448327b95d543, 0x70d38300a3340f1d, 0xde1c531c60e1c52b, 0x272224512c7de9e4}}}, -{{{0x1abc92af49c5342e, 0xffeed811b2e6fad0, 0xefa28c8dfcc84e29, 0x11b5df18a44cc543}}, - {{0xbf7bbb8a42a975fc, 0x8c5c397796ada358, 0xe27fc76fcdedaa48, 0x19735fd7f6bc20a6}}, - {{0xe3ab90d042c84266, 0xeb848e0f7f19547e, 0x2503a1d065a497b9, 0x0fef911191df895f}}}, -{{{0xb1507ca1ab1c6eb9, 0xbd448f3e16b687b3, 0x3455fb7f2c7a91ab, 0x7579229e2f2adec1}}, - {{0x6ab5dcb85b1c16b7, 0x94c0fce83c7b27a5, 0xa4b11c1a735517be, 0x499238d0ba0eafaa}}, - {{0xecf46e527aba8b57, 0x15a08c478bd1647b, 0x7af1c6a65f706fef, 0x6345fa78f03a30d5}}}, -{{{0xdf02f95f1015e7a1, 0x790ec41da9b40263, 0x4d3a0ea133ea1107, 0x54f70be7e33af8c9}}, - {{0x93d3cbe9bdd8f0a4, 0xdb152c1bfd177302, 0x7dbddc6d7f17a875, 0x3e1a71cc8f426efe}}, - {{0xc83ca3e390babd62, 0x80ede3670291c833, 0xc88038ccd37900c4, 0x2c5fc0231ec31fa1}}}, -{{{0xfeba911717038b4f, 0xe5123721c9deef81, 0x1c97e4e75d0d8834, 0x68afae7a23dc3bc6}}, - {{0xc422e4d102456e65, 0x87414ac1cad47b91, 0x1592e2bba2b6ffdd, 0x75d9d2bff5c2100f}}, - {{0x5bd9b4763626e81c, 0x89966936bca02edd, 0x0a41193d61f077b3, 0x3097a24200ce5471}}}, -{{{0x57427734c7f8b84c, 0xf141a13e01b270e9, 0x02d1adfeb4e564a6, 0x4bb23d92ce83bd48}}, - {{0xa162e7246695c486, 0x131d633435a89607, 0x30521561a0d12a37, 0x56704bada6afb363}}, - {{0xaf6c4aa752f912b9, 0x5e665f6cd86770c8, 0x4c35ac83a3c8cd58, 0x2b7a29c010a58a7e}}}, -{{{0xc4007f77d0c1cec3, 0x8d1020b6bac492f8, 0x32ec29d57e69daaf, 0x599408759d95fce0}}, - {{0x33810a23bf00086e, 0xafce925ee736ff7c, 0x3d60e670e24922d4, 0x11ce9e714f96061b}}, - {{0x219ef713d815bac1, 0xf141465d485be25c, 0x6d5447cc4e513c51, 0x174926be5ef44393}}}, -{{{0xb5deb2f9fc5bd5bb, 0x92daa72ae1d810e1, 0xafc4cfdcb72a1c59, 0x497d78813fc22a24}}, - {{0x3ef5d41593ea022e, 0x5cbcc1a20ed0eed6, 0x8fd24ecf07382c8c, 0x6fa42ead06d8e1ad}}, - {{0xe276824a1f73371f, 0x7f7cf01c4f5b6736, 0x7e201fe304fa46e7, 0x785a36a357808c96}}}, -{{{0x825fbdfd63014d2b, 0xc852369c6ca7578b, 0x5b2fcd285c0b5df0, 0x12ab214c58048c8f}}, - {{0x070442985d517bc3, 0x6acd56c7ae653678, 0x00a27983985a7763, 0x5167effae512662b}}, - {{0xbd4ea9e10f53c4b6, 0x1673dc5f8ac91a14, 0xa8f81a4e2acc1aba, 0x33a92a7924332a25}}}, -{{{0x9dd1f49927996c02, 0x0cb3b058e04d1752, 0x1f7e88967fd02c3e, 0x2f964268cb8b3eb1}}, - {{0x7ba95ba0218f2ada, 0xcff42287330fb9ca, 0xdada496d56c6d907, 0x5380c296f4beee54}}, - {{0x9d4f270466898d0a, 0x3d0987990aff3f7a, 0xd09ef36267daba45, 0x7761455e7b1c669c}}} \ No newline at end of file diff --git a/ext/ed25519-amd64-asm/ge25519_base_niels_smalltables.data b/ext/ed25519-amd64-asm/ge25519_base_niels_smalltables.data deleted file mode 100644 index a31f6f2f..00000000 --- a/ext/ed25519-amd64-asm/ge25519_base_niels_smalltables.data +++ /dev/null @@ -1,768 +0,0 @@ -{{{0x9d103905d740913e, 0xfd399f05d140beb3, 0xa5c18434688f8a09, 0x44fd2f9298f81267}}, - {{0x2fbc93c6f58c3b85, 0xcf932dc6fb8c0e19, 0x270b4898643d42c2, 0x07cf9d3a33d4ba65}}, - {{0xdbbd15674b6fbb59, 0x41e13f00eea2a5ea, 0xcdd49d1cc957c6fa, 0x4f0ebe1faf16ecca}}}, -{{{0x8a99a56042b4d5a8, 0x8f2b810c4e60acf6, 0xe09e236bb16e37aa, 0x6bb595a669c92555}}, - {{0x9224e7fc933c71d7, 0x9f469d967a0ff5b5, 0x5aa69a65e1d60702, 0x590c063fa87d2e2e}}, - {{0x6e347eaadad36802, 0xbaf3599383ee4805, 0x3bcabe10e6076826, 0x49314f0a165ed1b8}}}, -{{{0x56611fe8a4fcd265, 0x3bd353fde5c1ba7d, 0x8131f31a214bd6bd, 0x2ab91587555bda62}}, - {{0xaf25b0a84cee9730, 0x025a8430e8864b8a, 0xc11b50029f016732, 0x7a164e1b9a80f8f4}}, - {{0x9bf211f4f1674834, 0xb84e6b17f62df895, 0xd7de6f075b722a4e, 0x549a04b963bb2a21}}}, -{{{0x95fe050a056818bf, 0x327e89715660faa9, 0xc3e8e3cd06a05073, 0x27933f4c7445a49a}}, - {{0x287351b98efc099f, 0x6765c6f47dfd2538, 0xca348d3dfb0a9265, 0x680e910321e58727}}, - {{0xbf1e45ece51426b0, 0xe32bc63d6dba0f94, 0xe42974d58cf852c0, 0x44f079b1b0e64c18}}}, -{{{0x7f9182c3a447d6ba, 0xd50014d14b2729b7, 0xe33cf11cb864a087, 0x154a7e73eb1b55f3}}, - {{0xa212bc4408a5bb33, 0x8d5048c3c75eed02, 0xdd1beb0c5abfec44, 0x2945ccf146e206eb}}, - {{0xc832a179e7d003b3, 0x5f729d0a00124d7e, 0x62c1d4a10e6d8ff3, 0x68b8ac5938b27a98}}}, -{{{0x499806b67b7d8ca4, 0x575be28427d22739, 0xbb085ce7204553b9, 0x38b64c41ae417884}}, - {{0x3a0ceeeb77157131, 0x9b27158900c8af88, 0x8065b668da59a736, 0x51e57bb6a2cc38bd}}, - {{0x8f9dad91689de3a4, 0x175f2428f8fb9137, 0x050ab5329fcfb988, 0x7865dfa21354c09f}}}, -{{{0xba6f2c9aaa3221b1, 0x6ca021533bba23a7, 0x9dea764f92192c3a, 0x1d6edd5d2e5317e0}}, - {{0x6b1a5cd0944ea3bf, 0x7470353ab39dc0d2, 0x71b2528228542e49, 0x461bea69283c927e}}, - {{0x217a8aacab0fda36, 0xa528c6543d3549c8, 0x37d05b8b13ab7568, 0x233cef623a2cbc37}}}, -{{{0xe2a75dedf39234d9, 0x963d7680e1b558f9, 0x2c2741ac6e3c23fb, 0x3a9024a1320e01c3}}, - {{0x59b7596604dd3e8f, 0x6cb30377e288702c, 0xb1339c665ed9c323, 0x0915e76061bce52f}}, - {{0xdf7de835a834a37e, 0x8be19cda689857ea, 0x2c1185367167b326, 0x589eb3d9dbefd5c2}}}, -{{{0xed5b635449aa515e, 0xa865c49f0bc6823a, 0x850c1fe95b42d1c4, 0x30d76d6f03d315b9}}, - {{0x2eccdd0e632f9c1d, 0x51d0b69676893115, 0x52dfb76ba8637a58, 0x6dd37d49a00eef39}}, - {{0x6c4444172106e4c7, 0xfb53d680928d7f69, 0xb4739ea4694d3f26, 0x10c697112e864bb0}}}, -{{{0x6493c4277dbe5fde, 0x265d4fad19ad7ea2, 0x0e00dfc846304590, 0x25e61cabed66fe09}}, - {{0x0ca62aa08358c805, 0x6a3d4ae37a204247, 0x7464d3a63b11eddc, 0x03bf9baf550806ef}}, - {{0x3f13e128cc586604, 0x6f5873ecb459747e, 0xa0b63dedcc1268f5, 0x566d78634586e22c}}}, -{{{0x1637a49f9cc10834, 0xbc8e56d5a89bc451, 0x1cb5ec0f7f7fd2db, 0x33975bca5ecc35d9}}, - {{0xa1054285c65a2fd0, 0x6c64112af31667c3, 0x680ae240731aee58, 0x14fba5f34793b22a}}, - {{0x3cd746166985f7d4, 0x593e5e84c9c80057, 0x2fc3f2b67b61131e, 0x14829cea83fc526c}}}, -{{{0xff437b8497dd95c2, 0x6c744e30aa4eb5a7, 0x9e0c5d613c85e88b, 0x2fd9c71e5f758173}}, - {{0x21e70b2f4e71ecb8, 0xe656ddb940a477e3, 0xbf6556cece1d4f80, 0x05fc3bc4535d7b7e}}, - {{0x24b8b3ae52afdedd, 0x3495638ced3b30cf, 0x33a4bc83a9be8195, 0x373767475c651f04}}}, -{{{0x2fba99fd40d1add9, 0xb307166f96f4d027, 0x4363f05215f03bae, 0x1fbea56c3b18f999}}, - {{0x634095cb14246590, 0xef12144016c15535, 0x9e38140c8910bc60, 0x6bf5905730907c8c}}, - {{0x0fa778f1e1415b8a, 0x06409ff7bac3a77e, 0x6f52d7b89aa29a50, 0x02521cf67a635a56}}}, -{{{0x513fee0b0a9d5294, 0x8f98e75c0fdf5a66, 0xd4618688bfe107ce, 0x3fa00a7e71382ced}}, - {{0xb1146720772f5ee4, 0xe8f894b196079ace, 0x4af8224d00ac824a, 0x001753d9f7cd6cc4}}, - {{0x3c69232d963ddb34, 0x1dde87dab4973858, 0xaad7d1f9a091f285, 0x12b5fe2fa048edb6}}}, -{{{0x71f0fbc496fce34d, 0x73b9826badf35bed, 0xd2047261ff28c561, 0x749b76f96fb1206f}}, - {{0xdf2b7c26ad6f1e92, 0x4b66d323504b8913, 0x8c409dc0751c8bc3, 0x6f7e93c20796c7b8}}, - {{0x1f5af604aea6ae05, 0xc12351f1bee49c99, 0x61a808b5eeff6b66, 0x0fcec10f01e02151}}}, -{{{0x644d58a649fe1e44, 0x21fcaea231ad777e, 0x02441c5a887fd0d2, 0x4901aa7183c511f3}}, - {{0x3df2d29dc4244e45, 0x2b020e7493d8de0a, 0x6cc8067e820c214d, 0x413779166feab90a}}, - {{0x08b1b7548c1af8f0, 0xce0f7a7c246299b4, 0xf760b0f91e06d939, 0x41bb887b726d1213}}}, -{{{0x40e87d44744346be, 0x1d48dad415b52b25, 0x7c3a8a18a13b603e, 0x4eb728c12fcdbdf7}}, - {{0x7e234c597c6691ae, 0x64889d3d0a85b4c8, 0xdae2c90c354afae7, 0x0a871e070c6a9e1d}}, - {{0x3301b5994bbc8989, 0x736bae3a5bdd4260, 0x0d61ade219d59e3c, 0x3ee7300f2685d464}}}, -{{{0xf5d255e49e7dd6b7, 0x8016115c610b1eac, 0x3c99975d92e187ca, 0x13815762979125c2}}, - {{0x43fa7947841e7518, 0xe5c6fa59639c46d7, 0xa1065e1de3052b74, 0x7d47c6a2cfb89030}}, - {{0x3fdad0148ef0d6e0, 0x9d3e749a91546f3c, 0x71ec621026bb8157, 0x148cf58d34c9ec80}}}, -{{{0x46a492f67934f027, 0x469984bef6840aa9, 0x5ca1bc2a89611854, 0x3ff2fa1ebd5dbbd4}}, - {{0xe2572f7d9ae4756d, 0x56c345bb88f3487f, 0x9fd10b6d6960a88d, 0x278febad4eaea1b9}}, - {{0xb1aa681f8c933966, 0x8c21949c20290c98, 0x39115291219d3c52, 0x4104dd02fe9c677b}}}, -{{{0x72b2bf5e1124422a, 0xa1fa0c3398a33ab5, 0x94cb6101fa52b666, 0x2c863b00afaf53d5}}, - {{0x81214e06db096ab8, 0x21a8b6c90ce44f35, 0x6524c12a409e2af5, 0x0165b5a48efca481}}, - {{0xf190a474a0846a76, 0x12eff984cd2f7cc0, 0x695e290658aa2b8f, 0x591b67d9bffec8b8}}}, -{{{0x312f0d1c80b49bfa, 0x5979515eabf3ec8a, 0x727033c09ef01c88, 0x3de02ec7ca8f7bcb}}, - {{0x99b9b3719f18b55d, 0xe465e5faa18c641e, 0x61081136c29f05ed, 0x489b4f867030128b}}, - {{0xd232102d3aeb92ef, 0xe16253b46116a861, 0x3d7eabe7190baa24, 0x49f5fbba496cbebf}}}, -{{{0x30949a108a5bcfd4, 0xdc40dd70bc6473eb, 0x92c294c1307c0d1c, 0x5604a86dcbfa6e74}}, - {{0x155d628c1e9c572e, 0x8a4d86acc5884741, 0x91a352f6515763eb, 0x06a1a6c28867515b}}, - {{0x7288d1d47c1764b6, 0x72541140e0418b51, 0x9f031a6018acf6d1, 0x20989e89fe2742c6}}}, -{{{0x499777fd3a2dcc7f, 0x32857c2ca54fd892, 0xa279d864d207e3a0, 0x0403ed1d0ca67e29}}, - {{0x1674278b85eaec2e, 0x5621dc077acb2bdf, 0x640a4c1661cbf45a, 0x730b9950f70595d3}}, - {{0xc94b2d35874ec552, 0xc5e6c8cf98246f8d, 0xf7cb46fa16c035ce, 0x5bd7454308303dcc}}}, -{{{0x7f9ad19528b24cc2, 0x7f6b54656335c181, 0x66b8b66e4fc07236, 0x133a78007380ad83}}, - {{0x85c4932115e7792a, 0xc64c89a2bdcdddc9, 0x9d1e3da8ada3d762, 0x5bb7db123067f82c}}, - {{0x0961f467c6ca62be, 0x04ec21d6211952ee, 0x182360779bd54770, 0x740dca6d58f0e0d2}}}, -{{{0xdf48ee0752cfce4e, 0xc3fffaf306ec08b7, 0x05710b2ab95459c4, 0x161d25fa963ea38d}}, - {{0x231a8c570478433c, 0xb7b5270ec281439d, 0xdbaa99eae3d9079f, 0x2c03f5256c2b03d9}}, - {{0x790f18757b53a47d, 0x307b0130cf0c5879, 0x31903d77257ef7f9, 0x699468bdbd96bbaf}}}, -{{{0xbd1f2f46f4dafecf, 0x7cef0114a47fd6f7, 0xd31ffdda4a47b37f, 0x525219a473905785}}, - {{0xd8dd3de66aa91948, 0x485064c22fc0d2cc, 0x9b48246634fdea2f, 0x293e1c4e6c4a2e3a}}, - {{0x376e134b925112e1, 0x703778b5dca15da0, 0xb04589af461c3111, 0x5b605c447f032823}}}, -{{{0xb965805920c47c89, 0xe7f0100c923b8fcc, 0x0001256502e2ef77, 0x24a76dcea8aeb3ee}}, - {{0x3be9fec6f0e7f04c, 0x866a579e75e34962, 0x5542ef161e1de61a, 0x2f12fef4cc5abdd5}}, - {{0x0a4522b2dfc0c740, 0x10d06e7f40c9a407, 0xc6cf144178cff668, 0x5e607b2518a43790}}}, -{{{0x58b31d8f6cdf1818, 0x35cfa74fc36258a2, 0xe1b3ff4f66e61d6e, 0x5067acab6ccdd5f7}}, - {{0xa02c431ca596cf14, 0xe3c42d40aed3e400, 0xd24526802e0f26db, 0x201f33139e457068}}, - {{0xfd527f6b08039d51, 0x18b14964017c0006, 0xd5220eb02e25a4a8, 0x397cba8862460375}}}, -{{{0x30c13093f05959b2, 0xe23aa18de9a97976, 0x222fd491721d5e26, 0x2339d320766e6c3a}}, - {{0x7815c3fbc81379e7, 0xa6619420dde12af1, 0xffa9c0f885a8fdd5, 0x771b4022c1e1c252}}, - {{0xd87dd986513a2fa7, 0xf5ac9b71f9d4cf08, 0xd06bc31b1ea283b3, 0x331a189219971a76}}}, -{{{0xf5166f45fb4f80c6, 0x9c36c7de61c775cf, 0xe3d4e81b9041d91c, 0x31167c6b83bdfe21}}, - {{0x26512f3a9d7572af, 0x5bcbe28868074a9e, 0x84edc1c11180f7c4, 0x1ac9619ff649a67b}}, - {{0xf22b3842524b1068, 0x5068343bee9ce987, 0xfc9d71844a6250c8, 0x612436341f08b111}}}, -{{{0xd99d41db874e898d, 0x09fea5f16c07dc20, 0x793d2c67d00f9bbc, 0x46ebe2309e5eff40}}, - {{0x8b6349e31a2d2638, 0x9ddfb7009bd3fd35, 0x7f8bf1b8a3a06ba4, 0x1522aa3178d90445}}, - {{0x2c382f5369614938, 0xdafe409ab72d6d10, 0xe8c83391b646f227, 0x45fe70f50524306c}}}, -{{{0xda4875a6960c0b8c, 0x5b68d076ef0e2f20, 0x07fb51cf3d0b8fd4, 0x428d1623a0e392d4}}, - {{0x62f24920c8951491, 0x05f007c83f630ca2, 0x6fbb45d2f5c9d4b8, 0x16619f6db57a2245}}, - {{0x084f4a4401a308fd, 0xa82219c376a5caac, 0xdeb8de4643d1bc7d, 0x1d81592d60bd38c6}}}, -{{{0x61368756a60dac5f, 0x17e02f6aebabdc57, 0x7f193f2d4cce0f7d, 0x20234a7789ecdcf0}}, - {{0x8765b69f7b85c5e8, 0x6ff0678bd168bab2, 0x3a70e77c1d330f9b, 0x3a5f6d51b0af8e7c}}, - {{0x76d20db67178b252, 0x071c34f9d51ed160, 0xf62a4a20b3e41170, 0x7cd682353cffe366}}}, -{{{0x0be1a45bd887fab6, 0x2a846a32ba403b6e, 0xd9921012e96e6000, 0x2838c8863bdc0943}}, - {{0xa665cd6068acf4f3, 0x42d92d183cd7e3d3, 0x5759389d336025d9, 0x3ef0253b2b2cd8ff}}, - {{0xd16bb0cf4a465030, 0xfa496b4115c577ab, 0x82cfae8af4ab419d, 0x21dcb8a606a82812}}}, -{{{0x5c6004468c9d9fc8, 0x2540096ed42aa3cb, 0x125b4d4c12ee2f9c, 0x0bc3d08194a31dab}}, - {{0x9a8d00fabe7731ba, 0x8203607e629e1889, 0xb2cc023743f3d97f, 0x5d840dbf6c6f678b}}, - {{0x706e380d309fe18b, 0x6eb02da6b9e165c7, 0x57bbba997dae20ab, 0x3a4276232ac196dd}}}, -{{{0x4b42432c8a7084fa, 0x898a19e3dfb9e545, 0xbe9f00219c58e45d, 0x1ff177cea16debd1}}, - {{0x3bf8c172db447ecb, 0x5fcfc41fc6282dbd, 0x80acffc075aa15fe, 0x0770c9e824e1a9f9}}, - {{0xcf61d99a45b5b5fd, 0x860984e91b3a7924, 0xe7300919303e3e89, 0x39f264fd41500b1e}}}, -{{{0xa7ad3417dbe7e29c, 0xbd94376a2b9c139c, 0xa0e91b8e93597ba9, 0x1712d73468889840}}, - {{0xd19b4aabfe097be1, 0xa46dfce1dfe01929, 0xc3c908942ca6f1ff, 0x65c621272c35f14e}}, - {{0xe72b89f8ce3193dd, 0x4d103356a125c0bb, 0x0419a93d2e1cfe83, 0x22f9800ab19ce272}}}, -{{{0x605a368a3e9ef8cb, 0xe3e9c022a5504715, 0x553d48b05f24248f, 0x13f416cd647626e5}}, - {{0x42029fdd9a6efdac, 0xb912cebe34a54941, 0x640f64b987bdf37b, 0x4171a4d38598cab4}}, - {{0xfa2758aa99c94c8c, 0x23006f6fb000b807, 0xfbd291ddadda5392, 0x508214fa574bd1ab}}}, -{{{0xc20269153ed6fe4b, 0xa65a6739511d77c4, 0xcbde26462c14af94, 0x22f960ec6faba74b}}, - {{0x461a15bb53d003d6, 0xb2102888bcf3c965, 0x27c576756c683a5a, 0x3a7758a4c86cb447}}, - {{0x548111f693ae5076, 0x1dae21df1dfd54a6, 0x12248c90f3115e65, 0x5d9fd15f8de7f494}}}, -{{{0x031408d36d63727f, 0x6a379aefd7c7b533, 0xa9e18fc5ccaee24b, 0x332f35914f8fbed3}}, - {{0x3f244d2aeed7521e, 0x8e3a9028432e9615, 0xe164ba772e9c16d4, 0x3bc187fa47eb98d8}}, - {{0x6d470115ea86c20c, 0x998ab7cb6c46d125, 0xd77832b53a660188, 0x450d81ce906fba03}}}, -{{{0x6e7bb6a1a6205275, 0xaa4f21d7413c8e83, 0x6f56d155e88f5cb2, 0x2de25d4ba6345be1}}, - {{0xd074d8961cae743f, 0xf86d18f5ee1c63ed, 0x97bdc55be7f4ed29, 0x4cbad279663ab108}}, - {{0x80d19024a0d71fcd, 0xc525c20afb288af8, 0xb1a3974b5f3a6419, 0x7d7fbcefe2007233}}}, -{{{0xfaef1e6a266b2801, 0x866c68c4d5739f16, 0xf68a2fbc1b03762c, 0x5975435e87b75a8d}}, - {{0xcd7c5dc5f3c29094, 0xc781a29a2a9105ab, 0x80c61d36421c3058, 0x4f9cd196dcd8d4d7}}, - {{0x199297d86a7b3768, 0xd0d058241ad17a63, 0xba029cad5c1c0c17, 0x7ccdd084387a0307}}}, -{{{0xdca6422c6d260417, 0xae153d50948240bd, 0xa9c0c1b4fb68c677, 0x428bd0ed61d0cf53}}, - {{0x9b0c84186760cc93, 0xcdae007a1ab32a99, 0xa88dec86620bda18, 0x3593ca848190ca44}}, - {{0x9213189a5e849aa7, 0xd4d8c33565d8facd, 0x8c52545b53fdbbd1, 0x27398308da2d63e6}}}, -{{{0x42c38d28435ed413, 0xbd50f3603278ccc9, 0xbb07ab1a79da03ef, 0x269597aebe8c3355}}, - {{0xb9a10e4c0a702453, 0x0fa25866d57d1bde, 0xffb9d9b5cd27daf7, 0x572c2945492c33fd}}, - {{0xc77fc745d6cd30be, 0xe4dfe8d3e3baaefb, 0xa22c8830aa5dda0c, 0x7f985498c05bca80}}}, -{{{0x3849ce889f0be117, 0x8005ad1b7b54a288, 0x3da3c39f23fc921c, 0x76c2ec470a31f304}}, - {{0xd35615520fbf6363, 0x08045a45cf4dfba6, 0xeec24fbc873fa0c2, 0x30f2653cd69b12e7}}, - {{0x8a08c938aac10c85, 0x46179b60db276bcb, 0xa920c01e0e6fac70, 0x2f1273f1596473da}}}, -{{{0x4739fc7c8ae01e11, 0xfd5274904a6aab9f, 0x41d98a8287728f2e, 0x5d9e572ad85b69f2}}, - {{0x30488bd755a70bc0, 0x06d6b5a4f1d442e7, 0xead1a69ebc596162, 0x38ac1997edc5f784}}, - {{0x0666b517a751b13b, 0x747d06867e9b858c, 0xacacc011454dde49, 0x22dfcd9cbfe9e69c}}}, -{{{0x8ddbd2e0c30d0cd9, 0xad8e665facbb4333, 0x8f6b258c322a961f, 0x6b2916c05448c1c7}}, - {{0x56ec59b4103be0a1, 0x2ee3baecd259f969, 0x797cb29413f5cd32, 0x0fe9877824cde472}}, - {{0x7edb34d10aba913b, 0x4ea3cd822e6dac0e, 0x66083dff6578f815, 0x4c303f307ff00a17}}}, -{{{0xd30a3bd617b28c85, 0xc5d377b739773bea, 0xc6c6e78c1e6a5cbf, 0x0d61b8f78b2ab7c4}}, - {{0x29fc03580dd94500, 0xecd27aa46fbbec93, 0x130a155fc2e2a7f8, 0x416b151ab706a1d5}}, - {{0x56a8d7efe9c136b0, 0xbd07e5cd58e44b20, 0xafe62fda1b57e0ab, 0x191a2af74277e8d2}}}, -{{{0xce16f74bc53c1431, 0x2b9725ce2072edde, 0xb8b9c36fb5b23ee7, 0x7e2e0e450b5cc908}}, - {{0x9fe62b434f460efb, 0xded303d4a63607d6, 0xf052210eb7a0da24, 0x237e7dbe00545b93}}, - {{0x013575ed6701b430, 0x231094e69f0bfd10, 0x75320f1583e47f22, 0x71afa699b11155e3}}}, -{{{0x65ce6f9b3953b61d, 0xc65839eaafa141e6, 0x0f435ffda9f759fe, 0x021142e9c2b1c28e}}, - {{0xea423c1c473b50d6, 0x51e87a1f3b38ef10, 0x9b84bf5fb2c9be95, 0x00731fbc78f89a1c}}, - {{0xe430c71848f81880, 0xbf960c225ecec119, 0xb6dae0836bba15e3, 0x4c4d6f3347e15808}}}, -{{{0x18f7eccfc17d1fc9, 0x6c75f5a651403c14, 0xdbde712bf7ee0cdf, 0x193fddaaa7e47a22}}, - {{0x2f0cddfc988f1970, 0x6b916227b0b9f51b, 0x6ec7b6c4779176be, 0x38bf9500a88f9fa8}}, - {{0x1fd2c93c37e8876f, 0xa2f61e5a18d1462c, 0x5080f58239241276, 0x6a6fb99ebf0d4969}}}, -{{{0x6a46c1bb560855eb, 0x2416bb38f893f09d, 0xd71d11378f71acc1, 0x75f76914a31896ea}}, - {{0xeeb122b5b6e423c6, 0x939d7010f286ff8e, 0x90a92a831dcf5d8c, 0x136fda9f42c5eb10}}, - {{0xf94cdfb1a305bdd1, 0x0f364b9d9ff82c08, 0x2a87d8a5c3bb588a, 0x022183510be8dcba}}}, -{{{0x4af766385ead2d14, 0xa08ed880ca7c5830, 0x0d13a6e610211e3d, 0x6a071ce17b806c03}}, - {{0x9d5a710143307a7f, 0xb063de9ec47da45f, 0x22bbfe52be927ad3, 0x1387c441fd40426c}}, - {{0xb5d3c3d187978af8, 0x722b5a3d7f0e4413, 0x0d7b4848bb477ca0, 0x3171b26aaf1edc92}}}, -{{{0xa92f319097564ca8, 0xff7bb84c2275e119, 0x4f55fe37a4875150, 0x221fd4873cf0835a}}, - {{0xa60db7d8b28a47d1, 0xa6bf14d61770a4f1, 0xd4a1f89353ddbd58, 0x6c514a63344243e9}}, - {{0x2322204f3a156341, 0xfb73e0e9ba0a032d, 0xfce0dd4c410f030e, 0x48daa596fb924aaa}}}, -{{{0x6eca8e665ca59cc7, 0xa847254b2e38aca0, 0x31afc708d21e17ce, 0x676dd6fccad84af7}}, - {{0x14f61d5dc84c9793, 0x9941f9e3ef418206, 0xcdf5b88f346277ac, 0x58c837fa0e8a79a9}}, - {{0x0cf9688596fc9058, 0x1ddcbbf37b56a01b, 0xdcc2e77d4935d66a, 0x1c4f73f2c6a57f0a}}}, -{{{0x0e7a4fbd305fa0bb, 0x829d4ce054c663ad, 0xf421c3832fe33848, 0x795ac80d1bf64c42}}, - {{0xb36e706efc7c3484, 0x73dfc9b4c3c1cf61, 0xeb1d79c9781cc7e5, 0x70459adb7daf675c}}, - {{0x1b91db4991b42bb3, 0x572696234b02dcca, 0x9fdf9ee51f8c78dc, 0x5fe162848ce21fd3}}}, -{{{0x4e59214fe194961a, 0x49be7dc70d71cd4f, 0x9300cfd23b50f22d, 0x4789d446fc917232}}, - {{0x2879852d5d7cb208, 0xb8dedd70687df2e7, 0xdc0bffab21687891, 0x2b44c043677daa35}}, - {{0x1a1c87ab074eb78e, 0xfac6d18e99daf467, 0x3eacbbcd484f9067, 0x60c52eef2bb9a4e4}}}, -{{{0x0b5d89bc3bfd8bf1, 0xb06b9237c9f3551a, 0x0e4c16b0d53028f5, 0x10bc9c312ccfcaab}}, - {{0x702bc5c27cae6d11, 0x44c7699b54a48cab, 0xefbc4056ba492eb2, 0x70d77248d9b6676d}}, - {{0xaa8ae84b3ec2a05b, 0x98699ef4ed1781e0, 0x794513e4708e85d1, 0x63755bd3a976f413}}}, -{{{0xb55fa03e2ad10853, 0x356f75909ee63569, 0x9ff9f1fdbe69b890, 0x0d8cc1c48bc16f84}}, - {{0x3dc7101897f1acb7, 0x5dda7d5ec165bbd8, 0x508e5b9c0fa1020f, 0x2763751737c52a56}}, - {{0x029402d36eb419a9, 0xf0b44e7e77b460a5, 0xcfa86230d43c4956, 0x70c2dd8a7ad166e7}}}, -{{{0x656194509f6fec0e, 0xee2e7ea946c6518d, 0x9733c1f367e09b5c, 0x2e0fac6363948495}}, - {{0x91d4967db8ed7e13, 0x74252f0ad776817a, 0xe40982e00d852564, 0x32b8613816a53ce5}}, - {{0x79e7f7bee448cd64, 0x6ac83a67087886d0, 0xf89fd4d9a0e4db2e, 0x4179215c735a4f41}}}, -{{{0x8c7094e7d7dced2a, 0x97fb8ac347d39c70, 0xe13be033a906d902, 0x700344a30cd99d76}}, - {{0xe4ae33b9286bcd34, 0xb7ef7eb6559dd6dc, 0x278b141fb3d38e1f, 0x31fa85662241c286}}, - {{0xaf826c422e3622f4, 0xc12029879833502d, 0x9bc1b7e12b389123, 0x24bb2312a9952489}}}, -{{{0xb1a8ed1732de67c3, 0x3cb49418461b4948, 0x8ebd434376cfbcd2, 0x0fee3e871e188008}}, - {{0x41f80c2af5f85c6b, 0x687284c304fa6794, 0x8945df99a3ba1bad, 0x0d1d2af9ffeb5d16}}, - {{0xa9da8aa132621edf, 0x30b822a159226579, 0x4004197ba79ac193, 0x16acd79718531d76}}}, -{{{0x72df72af2d9b1d3d, 0x63462a36a432245a, 0x3ecea07916b39637, 0x123e0ef6b9302309}}, - {{0xc959c6c57887b6ad, 0x94e19ead5f90feba, 0x16e24e62a342f504, 0x164ed34b18161700}}, - {{0x487ed94c192fe69a, 0x61ae2cea3a911513, 0x877bf6d3b9a4de27, 0x78da0fc61073f3eb}}}, -{{{0x5bf15d28e52bc66a, 0x2c47e31870f01a8e, 0x2419afbc06c28bdd, 0x2d25deeb256b173a}}, - {{0xa29f80f1680c3a94, 0x71f77e151ae9e7e6, 0x1100f15848017973, 0x054aa4b316b38ddd}}, - {{0xdfc8468d19267cb8, 0x0b28789c66e54daf, 0x2aeb1d2a666eec17, 0x134610a6ab7da760}}}, -{{{0x51138ec78df6b0fe, 0x5397da89e575f51b, 0x09207a1d717af1b9, 0x2102fdba2b20d650}}, - {{0xcd2a65e777d1f515, 0x548991878faa60f1, 0xb1b73bbcdabc06e5, 0x654878cba97cc9fb}}, - {{0x969ee405055ce6a1, 0x36bca7681251ad29, 0x3a1af517aa7da415, 0x0ad725db29ecb2ba}}}, -{{{0xdc4267b1834e2457, 0xb67544b570ce1bc5, 0x1af07a0bf7d15ed7, 0x4aefcffb71a03650}}, - {{0xfec7bc0c9b056f85, 0x537d5268e7f5ffd7, 0x77afc6624312aefa, 0x4f675f5302399fd9}}, - {{0xc32d36360415171e, 0xcd2bef118998483b, 0x870a6eadd0945110, 0x0bccbb72a2a86561}}}, -{{{0x185e962feab1a9c8, 0x86e7e63565147dcd, 0xb092e031bb5b6df2, 0x4024f0ab59d6b73e}}, - {{0x186d5e4c50fe1296, 0xe0397b82fee89f7e, 0x3bc7f6c5507031b0, 0x6678fd69108f37c2}}, - {{0x1586fa31636863c2, 0x07f68c48572d33f2, 0x4f73cc9f789eaefc, 0x2d42e2108ead4701}}}, -{{{0x97f5131594dfd29b, 0x6155985d313f4c6a, 0xeba13f0708455010, 0x676b2608b8d2d322}}, - {{0x21717b0d0f537593, 0x914e690b131e064c, 0x1bb687ae752ae09f, 0x420bf3a79b423c6e}}, - {{0x8138ba651c5b2b47, 0x8671b6ec311b1b80, 0x7bff0cb1bc3135b0, 0x745d2ffa9c0cf1e0}}}, -{{{0xbf525a1e2bc9c8bd, 0xea5b260826479d81, 0xd511c70edf0155db, 0x1ae23ceb960cf5d0}}, - {{0x6036df5721d34e6a, 0xb1db8827997bb3d0, 0xd3c209c3c8756afa, 0x06e15be54c1dc839}}, - {{0x5b725d871932994a, 0x32351cb5ceb1dab0, 0x7dc41549dab7ca05, 0x58ded861278ec1f7}}}, -{{{0xd8173793f266c55c, 0xc8c976c5cc454e49, 0x5ce382f8bc26c3a8, 0x2ff39de85485f6f9}}, - {{0x2dfb5ba8b6c2c9a8, 0x48eeef8ef52c598c, 0x33809107f12d1573, 0x08ba696b531d5bd8}}, - {{0x77ed3eeec3efc57a, 0x04e05517d4ff4811, 0xea3d7a3ff1a671cb, 0x120633b4947cfe54}}}, -{{{0x0b94987891610042, 0x4ee7b13cecebfae8, 0x70be739594f0a4c0, 0x35d30a99b4d59185}}, - {{0x82bd31474912100a, 0xde237b6d7e6fbe06, 0xe11e761911ea79c6, 0x07433be3cb393bde}}, - {{0xff7944c05ce997f4, 0x575d3de4b05c51a3, 0x583381fd5a76847c, 0x2d873ede7af6da9f}}}, -{{{0x157a316443373409, 0xfab8b7eef4aa81d9, 0xb093fee6f5a64806, 0x2e773654707fa7b6}}, - {{0xaa6202e14e5df981, 0xa20d59175015e1f5, 0x18a275d3bae21d6c, 0x0543618a01600253}}, - {{0x0deabdf4974c23c1, 0xaa6f0a259dce4693, 0x04202cb8a29aba2c, 0x4b1443362d07960d}}}, -{{{0xccc4b7c7b66e1f7a, 0x44157e25f50c2f7e, 0x3ef06dfc713eaf1c, 0x582f446752da63f7}}, - {{0x967c54e91c529ccb, 0x30f6269264c635fb, 0x2747aff478121965, 0x17038418eaf66f5c}}, - {{0xc6317bd320324ce4, 0xa81042e8a4488bc4, 0xb21ef18b4e5a1364, 0x0c2a1c4bcda28dc9}}}, -{{{0xd24dc7d06f1f0447, 0xb2269e3edb87c059, 0xd15b0272fbb2d28f, 0x7c558bd1c6f64877}}, - {{0xedc4814869bd6945, 0x0d6d907dbe1c8d22, 0xc63bd212d55cc5ab, 0x5a6a9b30a314dc83}}, - {{0xd0ec1524d396463d, 0x12bb628ac35a24f0, 0xa50c3a791cbc5fa4, 0x0404a5ca0afbafc3}}}, -{{{0x8c1f40070aa743d6, 0xccbad0cb5b265ee8, 0x574b046b668fd2de, 0x46395bfdcadd9633}}, - {{0x62bc9e1b2a416fd1, 0xb5c6f728e350598b, 0x04343fd83d5d6967, 0x39527516e7f8ee98}}, - {{0x117fdb2d1a5d9a9c, 0x9c7745bcd1005c2a, 0xefd4bef154d56fea, 0x76579a29e822d016}}}, -{{{0x45b68e7e49c02a17, 0x23cd51a2bca9a37f, 0x3ed65f11ec224c1b, 0x43a384dc9e05bdb1}}, - {{0x333cb51352b434f2, 0xd832284993de80e1, 0xb5512887750d35ce, 0x02c514bb2a2777c1}}, - {{0x684bd5da8bf1b645, 0xfb8bd37ef6b54b53, 0x313916d7a9b0d253, 0x1160920961548059}}}, -{{{0xb44d166929dacfaa, 0xda529f4c8413598f, 0xe9ef63ca453d5559, 0x351e125bc5698e0b}}, - {{0x7a385616369b4dcd, 0x75c02ca7655c3563, 0x7dc21bf9d4f18021, 0x2f637d7491e6e042}}, - {{0xd4b49b461af67bbe, 0xd603037ac8ab8961, 0x71dee19ff9a699fb, 0x7f182d06e7ce2a9a}}}, -{{{0x7a7c8e64ab0168ec, 0xcb5a4a5515edc543, 0x095519d347cd0eda, 0x67d4ac8c343e93b0}}, - {{0x09454b728e217522, 0xaa58e8f4d484b8d8, 0xd358254d7f46903c, 0x44acc043241c5217}}, - {{0x1c7d6bbb4f7a5777, 0x8b35fed4918313e1, 0x4adca1c6c96b4684, 0x556d1c8312ad71bd}}}, -{{{0x17ef40e30c8d3982, 0x31f7073e15a3fa34, 0x4f21f3cb0773646e, 0x746c6c6d1d824eff}}, - {{0x81f06756b11be821, 0x0faff82310a3f3dd, 0xf8b2d0556a99465d, 0x097abe38cc8c7f05}}, - {{0x0c49c9877ea52da4, 0x4c4369559bdc1d43, 0x022c3809f7ccebd2, 0x577e14a34bee84bd}}}, -{{{0xf0e268ac61a73b0a, 0xf2fafa103791a5f5, 0xc1e13e826b6d00e9, 0x60fa7ee96fd78f42}}, - {{0x94fecebebd4dd72b, 0xf46a4fda060f2211, 0x124a5977c0c8d1ff, 0x705304b8fb009295}}, - {{0xb63d1d354d296ec6, 0xf3c3053e5fad31d8, 0x670b958cb4bd42ec, 0x21398e0ca16353fd}}}, -{{{0x89f5058a382b33f3, 0x5ae2ba0bad48c0b4, 0x8f93b503a53db36e, 0x5aa3ed9d95a232e6}}, - {{0x2798aaf9b4b75601, 0x5eac72135c8dad72, 0xd2ceaa6161b7a023, 0x1bbfb284e98f7d4e}}, - {{0x656777e9c7d96561, 0xcb2b125472c78036, 0x65053299d9506eee, 0x4a07e14e5e8957cc}}}, -{{{0x4ee412cb980df999, 0xa315d76f3c6ec771, 0xbba5edde925c77fd, 0x3f0bac391d313402}}, - {{0x240b58cdc477a49b, 0xfd38dade6447f017, 0x19928d32a7c86aad, 0x50af7aed84afa081}}, - {{0x6e4fde0115f65be5, 0x29982621216109b2, 0x780205810badd6d9, 0x1921a316baebd006}}}, -{{{0x89422f7edfb870fc, 0x2c296beb4f76b3bd, 0x0738f1d436c24df7, 0x6458df41e273aeb0}}, - {{0xd75aad9ad9f3c18b, 0x566a0eef60b1c19c, 0x3e9a0bac255c0ed9, 0x7b049deca062c7f5}}, - {{0xdccbe37a35444483, 0x758879330fedbe93, 0x786004c312c5dd87, 0x6093dccbc2950e64}}}, -{{{0x1ff39a8585e0706d, 0x36d0a5d8b3e73933, 0x43b9f2e1718f453b, 0x57d1ea084827a97c}}, - {{0x6bdeeebe6084034b, 0x3199c2b6780fb854, 0x973376abb62d0695, 0x6e3180c98b647d90}}, - {{0xee7ab6e7a128b071, 0xa4c1596d93a88baa, 0xf7b4de82b2216130, 0x363e999ddd97bd18}}}, -{{{0x96a843c135ee1fc4, 0x976eb35508e4c8cf, 0xb42f6801b58cd330, 0x48ee9b78693a052b}}, - {{0x2f1848dce24baec6, 0x769b7255babcaf60, 0x90cb3c6e3cefe931, 0x231f979bc6f9b355}}, - {{0x5c31de4bcc2af3c6, 0xb04bb030fe208d1f, 0xb78d7009c14fb466, 0x079bfa9b08792413}}}, -{{{0xe3903a51da300df4, 0x843964233da95ab0, 0xed3cf12d0b356480, 0x038c77f684817194}}, - {{0xf3c9ed80a2d54245, 0x0aa08b7877f63952, 0xd76dac63d1085475, 0x1ef4fb159470636b}}, - {{0x854e5ee65b167bec, 0x59590a4296d0cdc2, 0x72b2df3498102199, 0x575ee92a4a0bff56}}}, -{{{0xd4c080908a182fcf, 0x30e170c299489dbd, 0x05babd5752f733de, 0x43d4e7112cd3fd00}}, - {{0x5d46bc450aa4d801, 0xc3af1227a533b9d8, 0x389e3b262b8906c2, 0x200a1e7e382f581b}}, - {{0x518db967eaf93ac5, 0x71bc989b056652c0, 0xfe2b85d9567197f5, 0x050eca52651e4e38}}}, -{{{0xc3431ade453f0c9c, 0xe9f5045eff703b9b, 0xfcd97ac9ed847b3d, 0x4b0ee6c21c58f4c6}}, - {{0x97ac397660e668ea, 0x9b19bbfe153ab497, 0x4cb179b534eca79f, 0x6151c09fa131ae57}}, - {{0x3af55c0dfdf05d96, 0xdd262ee02ab4ee7a, 0x11b2bb8712171709, 0x1fef24fa800f030b}}}, -{{{0x37d653fb1aa73196, 0x0f9495303fd76418, 0xad200b09fb3a17b2, 0x544d49292fc8613e}}, - {{0x22d2aff530976b86, 0x8d90b806c2d24604, 0xdca1896c4de5bae5, 0x28005fe6c8340c17}}, - {{0x6aefba9f34528688, 0x5c1bff9425107da1, 0xf75bbbcd66d94b36, 0x72e472930f316dfa}}}, -{{{0x2695208c9781084f, 0xb1502a0b23450ee1, 0xfd9daea603efde02, 0x5a9d2e8c2733a34c}}, - {{0x07f3f635d32a7627, 0x7aaa4d865f6566f0, 0x3c85e79728d04450, 0x1fee7f000fe06438}}, - {{0x765305da03dbf7e5, 0xa4daf2491434cdbd, 0x7b4ad5cdd24a88ec, 0x00f94051ee040543}}}, -{{{0x8d356b23c3d330b2, 0xf21c8b9bb0471b06, 0xb36c316c6e42b83c, 0x07d79c7e8beab10d}}, - {{0xd7ef93bb07af9753, 0x583ed0cf3db766a7, 0xce6998bf6e0b1ec5, 0x47b7ffd25dd40452}}, - {{0x87fbfb9cbc08dd12, 0x8a066b3ae1eec29b, 0x0d57242bdb1fc1bf, 0x1c3520a35ea64bb6}}}, -{{{0x80d253a6bccba34a, 0x3e61c3a13838219b, 0x90c3b6019882e396, 0x1c3d05775d0ee66f}}, - {{0xcda86f40216bc059, 0x1fbb231d12bcd87e, 0xb4956a9e17c70990, 0x38750c3b66d12e55}}, - {{0x692ef1409422e51a, 0xcbc0c73c2b5df671, 0x21014fe7744ce029, 0x0621e2c7d330487c}}}, -{{{0xaf9860cc8259838d, 0x90ea48c1c69f9adc, 0x6526483765581e30, 0x0007d6097bd3a5bc}}, - {{0xb7ae1796b0dbf0f3, 0x54dfafb9e17ce196, 0x25923071e9aaa3b4, 0x5d8e589ca1002e9d}}, - {{0xc0bf1d950842a94b, 0xb2d3c363588f2e3e, 0x0a961438bb51e2ef, 0x1583d7783c1cbf86}}}, -{{{0xeceea2ef5da27ae1, 0x597c3a1455670174, 0xc9a62a126609167a, 0x252a5f2e81ed8f70}}, - {{0x90034704cc9d28c7, 0x1d1b679ef72cc58f, 0x16e12b5fbe5b8726, 0x4958064e83c5580a}}, - {{0x0d2894265066e80d, 0xfcc3f785307c8c6b, 0x1b53da780c1112fd, 0x079c170bd843b388}}}, -{{{0x0506ece464fa6fff, 0xbee3431e6205e523, 0x3579422451b8ea42, 0x6dec05e34ac9fb00}}, - {{0xcdd6cd50c0d5d056, 0x9af7686dbb03573b, 0x3ca6723ff3c3ef48, 0x6768c0d7317b8acc}}, - {{0x94b625e5f155c1b3, 0x417bf3a7997b7b91, 0xc22cbddc6d6b2600, 0x51445e14ddcd52f4}}}, -{{{0x57502b4b3b144951, 0x8e67ff6b444bbcb3, 0xb8bd6927166385db, 0x13186f31e39295c8}}, - {{0x893147ab2bbea455, 0x8c53a24f92079129, 0x4b49f948be30f7a7, 0x12e990086e4fd43d}}, - {{0xf10c96b37fdfbb2e, 0x9f9a935e121ceaf9, 0xdf1136c43a5b983f, 0x77b2e3f05d3e99af}}}, -{{{0x296fa9c59c2ec4de, 0xbc8b61bf4f84f3cb, 0x1c7706d917a8f908, 0x63b795fc7ad3255d}}, - {{0xd598639c12ddb0a4, 0xa5d19f30c024866b, 0xd17c2f0358fce460, 0x07a195152e095e8a}}, - {{0xa8368f02389e5fc8, 0x90433b02cf8de43b, 0xafa1fd5dc5412643, 0x3e8fe83d032f0137}}}, -{{{0x2f8b15b90570a294, 0x94f2427067084549, 0xde1c5ae161bbfd84, 0x75ba3b797fac4007}}, - {{0x08704c8de8efd13c, 0xdfc51a8e33e03731, 0xa59d5da51260cde3, 0x22d60899a6258c86}}, - {{0x6239dbc070cdd196, 0x60fe8a8b6c7d8a9a, 0xb38847bceb401260, 0x0904d07b87779e5e}}}, -{{{0xb4ce1fd4ddba919c, 0xcf31db3ec74c8daa, 0x2c63cc63ad86cc51, 0x43e2143fbc1dde07}}, - {{0xf4322d6648f940b9, 0x06952f0cbd2d0c39, 0x167697ada081f931, 0x6240aacebaf72a6c}}, - {{0xf834749c5ba295a0, 0xd6947c5bca37d25a, 0x66f13ba7e7c9316a, 0x56bdaf238db40cac}}}, -{{{0x362ab9e3f53533eb, 0x338568d56eb93d40, 0x9e0e14521d5a5572, 0x1d24a86d83741318}}, - {{0x1310d36cc19d3bb2, 0x062a6bb7622386b9, 0x7c9b8591d7a14f5c, 0x03aa31507e1e5754}}, - {{0xf4ec7648ffd4ce1f, 0xe045eaf054ac8c1c, 0x88d225821d09357c, 0x43b261dc9aeb4859}}}, -{{{0xe55b1e1988bb79bb, 0xa09ed07dc17a359d, 0xb02c2ee2603dea33, 0x326055cf5b276bc2}}, - {{0x19513d8b6c951364, 0x94fe7126000bf47b, 0x028d10ddd54f9567, 0x02b4d5e242940964}}, - {{0xb4a155cb28d18df2, 0xeacc4646186ce508, 0xc49cf4936c824389, 0x27a6c809ae5d3410}}}, -{{{0x8ba6ebcd1f0db188, 0x37d3d73a675a5be8, 0xf22edfa315f5585a, 0x2cb67174ff60a17e}}, - {{0xcd2c270ac43d6954, 0xdd4a3e576a66cab2, 0x79fa592469d7036c, 0x221503603d8c2599}}, - {{0x59eecdf9390be1d0, 0xa9422044728ce3f1, 0x82891c667a94f0f4, 0x7b1df4b73890f436}}}, -{{{0xe492f2e0b3b2a224, 0x7c6c9e062b551160, 0x15eb8fe20d7f7b0e, 0x61fcef2658fc5992}}, - {{0x5f2e221807f8f58c, 0xe3555c9fd49409d4, 0xb2aaa88d1fb6a630, 0x68698245d352e03d}}, - {{0xdbb15d852a18187a, 0xf3e4aad386ddacd7, 0x44bae2810ff6c482, 0x46cf4c473daf01cf}}}, -{{{0x426525ed9ec4e5f9, 0x0e5eda0116903303, 0x72b1a7f2cbe5cadc, 0x29387bcd14eb5f40}}, - {{0x213c6ea7f1498140, 0x7c1e7ef8392b4854, 0x2488c38c5629ceba, 0x1065aae50d8cc5bb}}, - {{0x1c2c4525df200d57, 0x5c3b2dd6bfca674a, 0x0a07e7b1e1834030, 0x69a198e64f1ce716}}}, -{{{0x9062b2e0d91a78bc, 0x47c9889cc8509667, 0x9df54a66405070b8, 0x7369e6a92493a1bf}}, - {{0xe1014434dcc5caed, 0x47ed5d963c84fb33, 0x70019576ed86a0e7, 0x25b2697bd267f9e4}}, - {{0x9d673ffb13986864, 0x3ca5fbd9415dc7b8, 0xe04ecc3bdf273b5e, 0x1420683db54e4cd2}}}, -{{{0xb478bd1e249dd197, 0x620c35005e58c102, 0xfb02d32fccbaac5c, 0x60b63bebf508a72d}}, - {{0x34eebb6fc1cc5ad0, 0x6a1b0ce99646ac8b, 0xd3b0da49a66bde53, 0x31e83b4161d081c1}}, - {{0x97e8c7129e062b4f, 0x49e48f4f29320ad8, 0x5bece14b6f18683f, 0x55cf1eb62d550317}}}, -{{{0x5879101065c23d58, 0x8b9d086d5094819c, 0xe2402fa912c55fa7, 0x669a6564570891d4}}, - {{0x3076b5e37df58c52, 0xd73ab9dde799cc36, 0xbd831ce34913ee20, 0x1a56fbaa62ba0133}}, - {{0x943e6b505c9dc9ec, 0x302557bba77c371a, 0x9873ae5641347651, 0x13c4836799c58a5c}}}, -{{{0x423a5d465ab3e1b9, 0xfc13c187c7f13f61, 0x19f83664ecb5b9b6, 0x66f80c93a637b607}}, - {{0xc4dcfb6a5d8bd080, 0xdeebc4ec571a4842, 0xd4b2e883b8e55365, 0x50bdc87dc8e5b827}}, - {{0x606d37836edfe111, 0x32353e15f011abd9, 0x64b03ac325b73b96, 0x1dd56444725fd5ae}}}, -{{{0x8fa47ff83362127d, 0xbc9f6ac471cd7c15, 0x6e71454349220c8b, 0x0e645912219f732e}}, - {{0xc297e60008bac89a, 0x7d4cea11eae1c3e0, 0xf3e38be19fe7977c, 0x3a3a450f63a305cd}}, - {{0x078f2f31d8394627, 0x389d3183de94a510, 0xd1e36c6d17996f80, 0x318c8d9393a9a87b}}}, -{{{0xf2745d032afffe19, 0x0c9f3c497f24db66, 0xbc98d3e3ba8598ef, 0x224c7c679a1d5314}}, - {{0x5d669e29ab1dd398, 0xfc921658342d9e3b, 0x55851dfdf35973cd, 0x509a41c325950af6}}, - {{0xbdc06edca6f925e9, 0x793ef3f4641b1f33, 0x82ec12809d833e89, 0x05bff02328a11389}}}, -{{{0x3632137023cae00b, 0x544acf0ad1accf59, 0x96741049d21a1c88, 0x780b8cc3fa2a44a7}}, - {{0x6881a0dd0dc512e4, 0x4fe70dc844a5fafe, 0x1f748e6b8f4a5240, 0x576277cdee01a3ea}}, - {{0x1ef38abc234f305f, 0x9a577fbd1405de08, 0x5e82a51434e62a0d, 0x5ff418726271b7a1}}}, -{{{0x398e080c1789db9d, 0xa7602025f3e778f5, 0xfa98894c06bd035d, 0x106a03dc25a966be}}, - {{0xe5db47e813b69540, 0xf35d2a3b432610e1, 0xac1f26e938781276, 0x29d4db8ca0a0cb69}}, - {{0xd9ad0aaf333353d0, 0x38669da5acd309e5, 0x3c57658ac888f7f0, 0x4ab38a51052cbefa}}}, -{{{0xda7c2b256768d593, 0x98c1c0574422ca13, 0xf1a80bd5ca0ace1d, 0x29cdd1adc088a690}}, - {{0xd6cfd1ef5fddc09c, 0xe82b3efdf7575dce, 0x25d56b5d201634c2, 0x3041c6bb04ed2b9b}}, - {{0x0ff2f2f9d956e148, 0xade797759f356b2e, 0x1a4698bb5f6c025c, 0x104bbd6814049a7b}}}, -{{{0x51f0fd3168f1ed67, 0x2c811dcdd86f3bc2, 0x44dc5c4304d2f2de, 0x5be8cc57092a7149}}, - {{0xa95d9a5fd67ff163, 0xe92be69d4cc75681, 0xb7f8024cde20f257, 0x204f2a20fb072df5}}, - {{0xc8143b3d30ebb079, 0x7589155abd652e30, 0x653c3c318f6d5c31, 0x2570fb17c279161f}}}, -{{{0x3efa367f2cb61575, 0xf5f96f761cd6026c, 0xe8c7142a65b52562, 0x3dcb65ea53030acd}}, - {{0x192ea9550bb8245a, 0xc8e6fba88f9050d1, 0x7986ea2d88a4c935, 0x241c5f91de018668}}, - {{0x28d8172940de6caa, 0x8fbf2cf022d9733a, 0x16d7fcdd235b01d1, 0x08420edd5fcdf0e5}}}, -{{{0xcdff20ab8362fa4a, 0x57e118d4e21a3e6e, 0xe3179617fc39e62b, 0x0d9a53efbc1769fd}}, - {{0x0358c34e04f410ce, 0xb6135b5a276e0685, 0x5d9670c7ebb91521, 0x04d654f321db889c}}, - {{0x5e7dc116ddbdb5d5, 0x2954deb68da5dd2d, 0x1cb608173334a292, 0x4a7a4f2618991ad7}}}, -{{{0xf4a718025fb15f95, 0x3df65f346b5c1b8f, 0xcdfcf08500e01112, 0x11b50c4cddd31848}}, - {{0x24c3b291af372a4b, 0x93da8270718147f2, 0xdd84856486899ef2, 0x4a96314223e0ee33}}, - {{0xa6e8274408a4ffd6, 0x738e177e9c1576d9, 0x773348b63d02b3f2, 0x4f4bce4dce6bcc51}}}, -{{{0xa71fce5ae2242584, 0x26ea725692f58a9e, 0xd21a09d71cea3cf4, 0x73fcdd14b71c01e6}}, - {{0x30e2616ec49d0b6f, 0xe456718fcaec2317, 0x48eb409bf26b4fa6, 0x3042cee561595f37}}, - {{0x427e7079449bac41, 0x855ae36dbce2310a, 0x4cae76215f841a7c, 0x389e740c9a9ce1d6}}}, -{{{0x64fcb3ae34dcb9ce, 0x97500323e348d0ad, 0x45b3f07d62c6381b, 0x61545379465a6788}}, - {{0xc9bd78f6570eac28, 0xe55b0b3227919ce1, 0x65fc3eaba19b91ed, 0x25c425e5d6263690}}, - {{0x3f3e06a6f1d7de6e, 0x3ef976278e062308, 0x8c14f6264e8a6c77, 0x6539a08915484759}}}, -{{{0xe9d21f74c3d2f773, 0xc150544125c46845, 0x624e5ce8f9b99e33, 0x11c5e4aac5cd186c}}, - {{0xddc4dbd414bb4a19, 0x19b2bc3c98424f8e, 0x48a89fd736ca7169, 0x0f65320ef019bd90}}, - {{0xd486d1b1cafde0c6, 0x4f3fe6e3163b5181, 0x59a8af0dfaf2939a, 0x4cabc7bdec33072a}}}, -{{{0x239e9624089c0a2e, 0xc748c4c03afe4738, 0x17dbed2a764fa12a, 0x639b93f0321c8582}}, - {{0xc08f788f3f78d289, 0xfe30a72ca1404d9f, 0xf2778bfccf65cc9d, 0x7ee498165acb2021}}, - {{0x7bd508e39111a1c3, 0x2b2b90d480907489, 0xe7d2aec2ae72fd19, 0x0edf493c85b602a6}}}, -{{{0xaecc8158599b5a68, 0xea574f0febade20e, 0x4fe41d7422b67f07, 0x403b92e3019d4fb4}}, - {{0x6767c4d284764113, 0xa090403ff7f5f835, 0x1c8fcffacae6bede, 0x04c00c54d1dfa369}}, - {{0x4dc22f818b465cf8, 0x71a0f35a1480eff8, 0xaee8bfad04c7d657, 0x355bb12ab26176f4}}}, -{{{0xa71e64cc7493bbf4, 0xe5bd84d9eca3b0c3, 0x0a6bc50cfa05e785, 0x0f9b8132182ec312}}, - {{0xa301dac75a8c7318, 0xed90039db3ceaa11, 0x6f077cbf3bae3f2d, 0x7518eaf8e052ad8e}}, - {{0xa48859c41b7f6c32, 0x0f2d60bcf4383298, 0x1815a929c9b1d1d9, 0x47c3871bbb1755c4}}}, -{{{0x5144539771ec4f48, 0xf805b17dc98c5d6e, 0xf762c11a47c3c66b, 0x00b89b85764699dc}}, - {{0xfbe65d50c85066b0, 0x62ecc4b0b3a299b0, 0xe53754ea441ae8e0, 0x08fea02ce8d48d5f}}, - {{0x824ddd7668deead0, 0xc86445204b685d23, 0xb514cfcd5d89d665, 0x473829a74f75d537}}}, -{{{0x82d2da754679c418, 0xe63bd7d8b2618df0, 0x355eef24ac47eb0a, 0x2078684c4833c6b4}}, - {{0x23d9533aad3902c9, 0x64c2ddceef03588f, 0x15257390cfe12fb4, 0x6c668b4d44e4d390}}, - {{0x3b48cf217a78820c, 0xf76a0ab281273e97, 0xa96c65a78c8eed7b, 0x7411a6054f8a433f}}}, -{{{0x4d659d32b99dc86d, 0x044cdc75603af115, 0xb34c712cdcc2e488, 0x7c136574fb8134ff}}, - {{0x579ae53d18b175b4, 0x68713159f392a102, 0x8455ecba1eef35f5, 0x1ec9a872458c398f}}, - {{0xb8e6a4d400a2509b, 0x9b81d7020bc882b4, 0x57e7cc9bf1957561, 0x3add88a5c7cd6460}}}, -{{{0xab895770b635dcf2, 0x02dfef6cf66c1fbc, 0x85530268beb6d187, 0x249929fccc879e74}}, - {{0x85c298d459393046, 0x8f7e35985ff659ec, 0x1d2ca22af2f66e3a, 0x61ba1131a406a720}}, - {{0xa3d0a0f116959029, 0x023b6b6cba7ebd89, 0x7bf15a3e26783307, 0x5620310cbbd8ece7}}}, -{{{0x528993434934d643, 0xb9dbf806a51222f5, 0x8f6d878fc3f41c22, 0x37676a2a4d9d9730}}, - {{0x6646b5f477e285d6, 0x40e8ff676c8f6193, 0xa6ec7311abb594dd, 0x7ec846f3658cec4d}}, - {{0x9b5e8f3f1da22ec7, 0x130f1d776c01cd13, 0x214c8fcfa2989fb8, 0x6daaf723399b9dd5}}}, -{{{0x5f3a7562eb3dbe47, 0xf7ea38548ebda0b8, 0x00c3e53145747299, 0x1304e9e71627d551}}, - {{0x583b04bfacad8ea2, 0x29b743e8148be884, 0x2b1e583b0810c5db, 0x2b5449e58eb3bbaa}}, - {{0x789814d26adc9cfe, 0x3c1bab3f8b48dd0b, 0xda0fe1fff979c60a, 0x4468de2d7c2dd693}}}, -{{{0x51bb355e9419469e, 0x33e6dc4c23ddc754, 0x93a5b6d6447f9962, 0x6cce7c6ffb44bd63}}, - {{0x4b9ad8c6f86307ce, 0x21113531435d0c28, 0xd4a866c5657a772c, 0x5da6427e63247352}}, - {{0x1a94c688deac22ca, 0xb9066ef7bbae1ff8, 0x88ad8c388d59580f, 0x58f29abfe79f2ca8}}}, -{{{0xe90ecfab8de73e68, 0x54036f9f377e76a5, 0xf0495b0bbe015982, 0x577629c4a7f41e36}}, - {{0x4b5a64bf710ecdf6, 0xb14ce538462c293c, 0x3643d056d50b3ab9, 0x6af93724185b4870}}, - {{0x3220024509c6a888, 0xd2e036134b558973, 0x83e236233c33289f, 0x701f25bb0caec18f}}}, -{{{0xc3a8b0f8e4616ced, 0xf700660e9e25a87d, 0x61e3061ff4bca59c, 0x2e0c92bfbdc40be9}}, - {{0x9d18f6d97cbec113, 0x844a06e674bfdbe4, 0x20f5b522ac4e60d6, 0x720a5bc050955e51}}, - {{0x0c3f09439b805a35, 0xe84e8b376242abfc, 0x691417f35c229346, 0x0e9b9cbb144ef0ec}}}, -{{{0xfbbad48ffb5720ad, 0xee81916bdbf90d0e, 0xd4813152635543bf, 0x221104eb3f337bd8}}, - {{0x8dee9bd55db1beee, 0xc9c3ab370a723fb9, 0x44a8f1bf1c68d791, 0x366d44191cfd3cde}}, - {{0x9e3c1743f2bc8c14, 0x2eda26fcb5856c3b, 0xccb82f0e68a7fb97, 0x4167a4e6bc593244}}}, -{{{0x643b9d2876f62700, 0x5d1d9d400e7668eb, 0x1b4b430321fc0684, 0x7938bb7e2255246a}}, - {{0xc2be2665f8ce8fee, 0xe967ff14e880d62c, 0xf12e6e7e2f364eee, 0x34b33370cb7ed2f6}}, - {{0xcdc591ee8681d6cc, 0xce02109ced85a753, 0xed7485c158808883, 0x1176fc6e2dfe65e4}}}, -{{{0xb4af6cd05b9c619b, 0x2ddfc9f4b2a58480, 0x3d4fa502ebe94dc4, 0x08fc3a4c677d5f34}}, - {{0xdb90e28949770eb8, 0x98fbcc2aacf440a3, 0x21354ffeded7879b, 0x1f6a3e54f26906b6}}, - {{0x60a4c199d30734ea, 0x40c085b631165cd6, 0xe2333e23f7598295, 0x4f2fad0116b900d1}}}, -{{{0x44beb24194ae4e54, 0x5f541c511857ef6c, 0xa61e6b2d368d0498, 0x445484a4972ef7ab}}, - {{0x962cd91db73bb638, 0xe60577aafc129c08, 0x6f619b39f3b61689, 0x3451995f2944ee81}}, - {{0x9152fcd09fea7d7c, 0x4a816c94b0935cf6, 0x258e9aaa47285c40, 0x10b89ca6042893b7}}}, -{{{0x3d5947499718289c, 0x12ebf8c524533f26, 0x0262bfcb14c3ef15, 0x20b878d577b7518e}}, - {{0x753941be5a45f06e, 0xd07caeed6d9c5f65, 0x11776b9c72ff51b6, 0x17d2d1d9ef0d4da9}}, - {{0x27f2af18073f3e6a, 0xfd3fe519d7521069, 0x22e3b72c3ca60022, 0x72214f63cc65c6a7}}}, -{{{0xb4e37f405307a693, 0xaba714d72f336795, 0xd6fbd0a773761099, 0x5fdf48c58171cbc9}}, - {{0x1d9db7b9f43b29c9, 0xd605824a4f518f75, 0xf2c072bd312f9dc4, 0x1f24ac855a1545b0}}, - {{0x24d608328e9505aa, 0x4748c1d10c1420ee, 0xc7ffe45c06fb25a2, 0x00ba739e2ae395e6}}}, -{{{0x592e98de5c8790d6, 0xe5bfb7d345c2a2df, 0x115a3b60f9b49922, 0x03283a3e67ad78f3}}, - {{0xae4426f5ea88bb26, 0x360679d984973bfb, 0x5c9f030c26694e50, 0x72297de7d518d226}}, - {{0x48241dc7be0cb939, 0x32f19b4d8b633080, 0xd3dfc90d02289308, 0x05e1296846271945}}}, -{{{0xba82eeb32d9c495a, 0xceefc8fcf12bb97c, 0xb02dabae93b5d1e0, 0x39c00c9c13698d9b}}, - {{0xadbfbbc8242c4550, 0xbcc80cecd03081d9, 0x843566a6f5c8df92, 0x78cf25d38258ce4c}}, - {{0x15ae6b8e31489d68, 0xaa851cab9c2bf087, 0xc9a75a97f04efa05, 0x006b52076b3ff832}}}, -{{{0x29e0cfe19d95781c, 0xb681df18966310e2, 0x57df39d370516b39, 0x4d57e3443bc76122}}, - {{0xf5cb7e16b9ce082d, 0x3407f14c417abc29, 0xd4b36bce2bf4a7ab, 0x7de2e9561a9f75ce}}, - {{0xde70d4f4b6a55ecb, 0x4801527f5d85db99, 0xdbc9c440d3ee9a81, 0x6b2a90af1a6029ed}}}, -{{{0x6923f4fc9ae61e97, 0x5735281de03f5fd1, 0xa764ae43e6edd12d, 0x5fd8f4e9d12d3e4a}}, - {{0x77ebf3245bb2d80a, 0xd8301b472fb9079b, 0xc647e6f24cee7333, 0x465812c8276c2109}}, - {{0x4d43beb22a1062d9, 0x7065fb753831dc16, 0x180d4a7bde2968d7, 0x05b32c2b1cb16790}}}, -{{{0xc8c05eccd24da8fd, 0xa1cf1aac05dfef83, 0xdbbeeff27df9cd61, 0x3b5556a37b471e99}}, - {{0xf7fca42c7ad58195, 0x3214286e4333f3cc, 0xb6c29d0d340b979d, 0x31771a48567307e1}}, - {{0x32b0c524e14dd482, 0xedb351541a2ba4b6, 0xa3d16048282b5af3, 0x4fc079d27a7336eb}}}, -{{{0x51c938b089bf2f7f, 0x2497bd6502dfe9a7, 0xffffc09c7880e453, 0x124567cecaf98e92}}, - {{0xdc348b440c86c50d, 0x1337cbc9cc94e651, 0x6422f74d643e3cb9, 0x241170c2bae3cd08}}, - {{0x3ff9ab860ac473b4, 0xf0911dee0113e435, 0x4ae75060ebc6c4af, 0x3f8612966c87000d}}}, -{{{0x559a0cc9782a0dde, 0x551dcdb2ea718385, 0x7f62865b31ef238c, 0x504aa7767973613d}}, - {{0x9c18fcfa36048d13, 0x29159db373899ddd, 0xdc9f350b9f92d0aa, 0x26f57eee878a19d4}}, - {{0x0cab2cd55687efb1, 0x5180d162247af17b, 0x85c15a344f5a2467, 0x4041943d9dba3069}}}, -{{{0xc3c0eeba43ebcc96, 0x8d749c9c26ea9caf, 0xd9fa95ee1c77ccc6, 0x1420a1d97684340f}}, - {{0x4b217743a26caadd, 0x47a6b424648ab7ce, 0xcb1d4f7a03fbc9e3, 0x12d931429800d019}}, - {{0x00c67799d337594f, 0x5e3c5140b23aa47b, 0x44182854e35ff395, 0x1b4f92314359a012}}}, -{{{0x3e5c109d89150951, 0x39cefa912de9696a, 0x20eae43f975f3020, 0x239b572a7f132dae}}, - {{0x33cf3030a49866b1, 0x251f73d2215f4859, 0xab82aa4051def4f6, 0x5ff191d56f9a23f6}}, - {{0x819ed433ac2d9068, 0x2883ab795fc98523, 0xef4572805593eb3d, 0x020c526a758f36cb}}}, -{{{0x779834f89ed8dbbc, 0xc8f2aaf9dc7ca46c, 0xa9524cdca3e1b074, 0x02aacc4615313877}}, - {{0xe931ef59f042cc89, 0x2c589c9d8e124bb6, 0xadc8e18aaec75997, 0x452cfe0a5602c50c}}, - {{0x86a0f7a0647877df, 0xbbc464270e607c9f, 0xab17ea25f1fb11c9, 0x4cfb7d7b304b877b}}}, -{{{0x72b43d6cb89b75fe, 0x54c694d99c6adc80, 0xb8c3aa373ee34c9f, 0x14b4622b39075364}}, - {{0xe28699c29789ef12, 0x2b6ecd71df57190d, 0xc343c857ecc970d0, 0x5b1d4cbc434d3ac5}}, - {{0xb6fb2615cc0a9f26, 0x3a4f0e2bb88dcce5, 0x1301498b3369a705, 0x2f98f71258592dd1}}}, -{{{0x0c94a74cb50f9e56, 0x5b1ff4a98e8e1320, 0x9a2acc2182300f67, 0x3a6ae249d806aaf9}}, - {{0x2e12ae444f54a701, 0xfcfe3ef0a9cbd7de, 0xcebf890d75835de0, 0x1d8062e9e7614554}}, - {{0x657ada85a9907c5a, 0x1a0ea8b591b90f62, 0x8d0e1dfbdf34b4e9, 0x298b8ce8aef25ff3}}}, -{{{0x2a927953eff70cb2, 0x4b89c92a79157076, 0x9418457a30a7cf6a, 0x34b8a8404d5ce485}}, - {{0x837a72ea0a2165de, 0x3fab07b40bcf79f6, 0x521636c77738ae70, 0x6ba6271803a7d7dc}}, - {{0xc26eecb583693335, 0xd5a813df63b5fefd, 0xa293aa9aa4b22573, 0x71d62bdd465e1c6a}}}, -{{{0x6533cc28d378df80, 0xf6db43790a0fa4b4, 0xe3645ff9f701da5a, 0x74d5f317f3172ba4}}, - {{0xcd2db5dab1f75ef5, 0xd77f95cf16b065f5, 0x14571fea3f49f085, 0x1c333621262b2b3d}}, - {{0xa86fe55467d9ca81, 0x398b7c752b298c37, 0xda6d0892e3ac623b, 0x4aebcc4547e9d98c}}}, -{{{0x12f0071b276d01c9, 0xe7b8bac586c48c70, 0x5308129b71d6fba9, 0x5d88fbf95a3db792}}, - {{0x0b408d9e7354b610, 0x806b32535ba85b6e, 0xdbe63a034a58a207, 0x173bd9ddc9a1df2c}}, - {{0x2b500f1efe5872df, 0x58d6582ed43918c1, 0xe6ed278ec9673ae0, 0x06e1cd13b19ea319}}}, -{{{0x40d0ad516f166f23, 0x118e32931fab6abe, 0x3fe35e14a04d088e, 0x3080603526e16266}}, - {{0x472baf629e5b0353, 0x3baa0b90278d0447, 0x0c785f469643bf27, 0x7f3a6a1a8d837b13}}, - {{0xf7e644395d3d800b, 0x95a8d555c901edf6, 0x68cd7830592c6339, 0x30d0fded2e51307e}}}, -{{{0xe0594d1af21233b3, 0x1bdbe78ef0cc4d9c, 0x6965187f8f499a77, 0x0a9214202c099868}}, - {{0x9cb4971e68b84750, 0xa09572296664bbcf, 0x5c8de72672fa412b, 0x4615084351c589d9}}, - {{0xbc9019c0aeb9a02e, 0x55c7110d16034cae, 0x0e6df501659932ec, 0x3bca0d2895ca5dfe}}}, -{{{0x40f031bc3c5d62a4, 0x19fc8b3ecff07a60, 0x98183da2130fb545, 0x5631deddae8f13cd}}, - {{0x9c688eb69ecc01bf, 0xf0bc83ada644896f, 0xca2d955f5f7a9fe2, 0x4ea8b4038df28241}}, - {{0x2aed460af1cad202, 0x46305305a48cee83, 0x9121774549f11a5f, 0x24ce0930542ca463}}}, -{{{0x1fe890f5fd06c106, 0xb5c468355d8810f2, 0x827808fe6e8caf3e, 0x41d4e3c28a06d74b}}, - {{0x3fcfa155fdf30b85, 0xd2f7168e36372ea4, 0xb2e064de6492f844, 0x549928a7324f4280}}, - {{0xf26e32a763ee1a2e, 0xae91e4b7d25ffdea, 0xbc3bd33bd17f4d69, 0x491b66dec0dcff6a}}}, -{{{0x98f5b13dc7ea32a7, 0xe3d5f8cc7e16db98, 0xac0abf52cbf8d947, 0x08f338d0c85ee4ac}}, - {{0x75f04a8ed0da64a1, 0xed222caf67e2284b, 0x8234a3791f7b7ba4, 0x4cf6b8b0b7018b67}}, - {{0xc383a821991a73bd, 0xab27bc01df320c7a, 0xc13d331b84777063, 0x530d4a82eb078a99}}}, -{{{0x004c3630e1f94825, 0x7e2d78268cab535a, 0xc7482323cc84ff8b, 0x65ea753f101770b9}}, - {{0x6d6973456c9abf9e, 0x257fb2fc4900a880, 0x2bacf412c8cfb850, 0x0db3e7e00cbfbd5b}}, - {{0x3d66fc3ee2096363, 0x81d62c7f61b5cb6b, 0x0fbe044213443b1a, 0x02a4ec1921e1a1db}}}, -{{{0x5ce6259a3b24b8a2, 0xb8577acc45afa0b8, 0xcccbe6e88ba07037, 0x3d143c51127809bf}}, - {{0xf5c86162f1cf795f, 0x118c861926ee57f2, 0x172124851c063578, 0x36d12b5dec067fcf}}, - {{0x126d279179154557, 0xd5e48f5cfc783a0a, 0x36bdb6e8df179bac, 0x2ef517885ba82859}}}, -{{{0x4637974e8c58aedc, 0xb9ef22fbabf041a4, 0xe185d956e980718a, 0x2f1b78fab143a8a6}}, - {{0x96eebffb305b2f51, 0xd3f938ad889596b8, 0xf0f52dc746d5dd25, 0x57968290bb3a0095}}, - {{0xf71ab8430a20e101, 0xf393658d24f0ec47, 0xcf7509a86ee2eed1, 0x7dc43e35dc2aa3e1}}}, -{{{0x85966665887dd9c3, 0xc90f9b314bb05355, 0xc6e08df8ef2079b1, 0x7ef72016758cc12f}}, - {{0x5a782a5c273e9718, 0x3576c6995e4efd94, 0x0f2ed8051f237d3e, 0x044fb81d82d50a99}}, - {{0xc1df18c5a907e3d9, 0x57b3371dce4c6359, 0xca704534b201bb49, 0x7f79823f9c30dd2e}}}, -{{{0x8334d239a3b513e8, 0xc13670d4b91fa8d8, 0x12b54136f590bd33, 0x0a4e0373d784d9b4}}, - {{0x6a9c1ff068f587ba, 0x0827894e0050c8de, 0x3cbf99557ded5be7, 0x64a9b0431c06d6f0}}, - {{0x2eb3d6a15b7d2919, 0xb0b4f6a0d53a8235, 0x7156ce4389a45d47, 0x071a7d0ace18346c}}}, -{{{0xd3072daac887ba0b, 0x01262905bfa562ee, 0xcf543002c0ef768b, 0x2c3bcc7146ea7e9c}}, - {{0xcc0c355220e14431, 0x0d65950709b15141, 0x9af5621b209d5f36, 0x7c69bcf7617755d3}}, - {{0x07f0d7eb04e8295f, 0x10db18252f50f37d, 0xe951a9a3171798d7, 0x6f5a9a7322aca51d}}}, -{{{0x8ba1000c2f41c6c5, 0xc49f79c10cfefb9b, 0x4efa47703cc51c9f, 0x494e21a2e147afca}}, - {{0xe729d4eba3d944be, 0x8d9e09408078af9e, 0x4525567a47869c03, 0x02ab9680ee8d3b24}}, - {{0xefa48a85dde50d9a, 0x219a224e0fb9a249, 0xfa091f1dd91ef6d9, 0x6b5d76cbea46bb34}}}, -{{{0x8857556cec0cd994, 0x6472dc6f5cd01dba, 0xaf0169148f42b477, 0x0ae333f685277354}}, - {{0xe0f941171e782522, 0xf1e6ae74036936d3, 0x408b3ea2d0fcc746, 0x16fb869c03dd313e}}, - {{0x288e199733b60962, 0x24fc72b4d8abe133, 0x4811f7ed0991d03e, 0x3f81e38b8f70d075}}}, -{{{0x7f910fcc7ed9affe, 0x545cb8a12465874b, 0xa8397ed24b0c4704, 0x50510fc104f50993}}, - {{0x0adb7f355f17c824, 0x74b923c3d74299a4, 0xd57c3e8bcbf8eaf7, 0x0ad3e2d34cdedc3d}}, - {{0x6f0c0fc5336e249d, 0x745ede19c331cfd9, 0xf2d6fd0009eefe1c, 0x127c158bf0fa1ebe}}}, -{{{0xf6197c422e9879a2, 0xa44addd452ca3647, 0x9b413fc14b4eaccb, 0x354ef87d07ef4f68}}, - {{0xdea28fc4ae51b974, 0x1d9973d3744dfe96, 0x6240680b873848a8, 0x4ed82479d167df95}}, - {{0xfee3b52260c5d975, 0x50352efceb41b0b8, 0x8808ac30a9f6653c, 0x302d92d20539236d}}}, -{{{0x7813c1a2bca4283d, 0xed62f091a1863dd9, 0xaec7bcb8c268fa86, 0x10e5d3b76f1cae4c}}, - {{0x2dbc6fb6e4e0f177, 0x04e1bf29a4bd6a93, 0x5e1966d4787af6e8, 0x0edc5f5eb426d060}}, - {{0x5453bfd653da8e67, 0xe9dc1eec24a9f641, 0xbf87263b03578a23, 0x45b46c51361cba72}}}, -{{{0xa9402abf314f7fa1, 0xe257f1dc8e8cf450, 0x1dbbd54b23a8be84, 0x2177bfa36dcb713b}}, - {{0xce9d4ddd8a7fe3e4, 0xab13645676620e30, 0x4b594f7bb30e9958, 0x5c1c0aef321229df}}, - {{0x37081bbcfa79db8f, 0x6048811ec25f59b3, 0x087a76659c832487, 0x4ae619387d8ab5bb}}}, -{{{0x8ddbf6aa5344a32e, 0x7d88eab4b41b4078, 0x5eb0eb974a130d60, 0x1a00d91b17bf3e03}}, - {{0x61117e44985bfb83, 0xfce0462a71963136, 0x83ac3448d425904b, 0x75685abe5ba43d64}}, - {{0x6e960933eb61f2b2, 0x543d0fa8c9ff4952, 0xdf7275107af66569, 0x135529b623b0e6aa}}}, -{{{0x18f0dbd7add1d518, 0x979f7888cfc11f11, 0x8732e1f07114759b, 0x79b5b81a65ca3a01}}, - {{0xf5c716bce22e83fe, 0xb42beb19e80985c1, 0xec9da63714254aae, 0x5972ea051590a613}}, - {{0x0fd4ac20dc8f7811, 0x9a9ad294ac4d4fa8, 0xc01b2d64b3360434, 0x4f7e9c95905f3bdb}}}, -{{{0x62674bbc5781302e, 0xd8520f3989addc0f, 0x8c2999ae53fbd9c6, 0x31993ad92e638e4c}}, - {{0x71c8443d355299fe, 0x8bcd3b1cdbebead7, 0x8092499ef1a49466, 0x1942eec4a144adc8}}, - {{0x7dac5319ae234992, 0x2c1b3d910cea3e92, 0x553ce494253c1122, 0x2a0a65314ef9ca75}}}, -{{{0x2db7937ff7f927c2, 0xdb741f0617d0a635, 0x5982f3a21155af76, 0x4cf6e218647c2ded}}, - {{0xcf361acd3c1c793a, 0x2f9ebcac5a35bc3b, 0x60e860e9a8cda6ab, 0x055dc39b6dea1a13}}, - {{0xb119227cc28d5bb6, 0x07e24ebc774dffab, 0xa83c78cee4a32c89, 0x121a307710aa24b6}}}, -{{{0xe4db5d5e9f034a97, 0xe153fc093034bc2d, 0x460546919551d3b1, 0x333fc76c7a40e52d}}, - {{0xd659713ec77483c9, 0x88bfe077b82b96af, 0x289e28231097bcd3, 0x527bb94a6ced3a9b}}, - {{0x563d992a995b482e, 0x3405d07c6e383801, 0x485035de2f64d8e5, 0x6b89069b20a7a9f7}}}, -{{{0x812aa0416270220d, 0x995a89faf9245b4e, 0xffadc4ce5072ef05, 0x23bc2103aa73eb73}}, - {{0x4082fa8cb5c7db77, 0x068686f8c734c155, 0x29e6c8d9f6e7a57e, 0x0473d308a7639bcf}}, - {{0xcaee792603589e05, 0x2b4b421246dcc492, 0x02a1ef74e601a94f, 0x102f73bfde04341a}}}, -{{{0xeb18b9ab7f5745c6, 0x023a8aee5787c690, 0xb72712da2df7afa9, 0x36597d25ea5c013d}}, - {{0xa2b4dae0b5511c9a, 0x7ac860292bffff06, 0x981f375df5504234, 0x3f6bd725da4ea12d}}, - {{0x734d8d7b106058ac, 0xd940579e6fc6905f, 0x6466f8f99202932d, 0x7b7ecc19da60d6d0}}}, -{{{0x78c2373c695c690d, 0xdd252e660642906e, 0x951d44444ae12bd2, 0x4235ad7601743956}}, - {{0x6dae4a51a77cfa9b, 0x82263654e7a38650, 0x09bbffcd8f2d82db, 0x03bedc661bf5caba}}, - {{0x6258cb0d078975f5, 0x492942549189f298, 0xa0cab423e2e36ee4, 0x0e7ce2b0cdf066a1}}}, -{{{0xc494643ac48c85a3, 0xfd361df43c6139ad, 0x09db17dd3ae94d48, 0x666e0a5d8fb4674a}}, - {{0xfea6fedfd94b70f9, 0xf130c051c1fcba2d, 0x4882d47e7f2fab89, 0x615256138aeceeb5}}, - {{0x2abbf64e4870cb0d, 0xcd65bcf0aa458b6b, 0x9abe4eba75e8985d, 0x7f0bc810d514dee4}}}, -{{{0xb9006ba426f4136f, 0x8d67369e57e03035, 0xcbc8dfd94f463c28, 0x0d1f8dbcf8eedbf5}}, - {{0x83ac9dad737213a0, 0x9ff6f8ba2ef72e98, 0x311e2edd43ec6957, 0x1d3a907ddec5ab75}}, - {{0xba1693313ed081dc, 0x29329fad851b3480, 0x0128013c030321cb, 0x00011b44a31bfde3}}}, -{{{0x3fdfa06c3fc66c0c, 0x5d40e38e4dd60dd2, 0x7ae38b38268e4d71, 0x3ac48d916e8357e1}}, - {{0x16561f696a0aa75c, 0xc1bf725c5852bd6a, 0x11a8dd7f9a7966ad, 0x63d988a2d2851026}}, - {{0x00120753afbd232e, 0xe92bceb8fdd8f683, 0xf81669b384e72b91, 0x33fad52b2368a066}}}, -{{{0x540649c6c5e41e16, 0x0af86430333f7735, 0xb2acfcd2f305e746, 0x16c0f429a256dca7}}, - {{0x8d2cc8d0c422cfe8, 0x072b4f7b05a13acb, 0xa3feb6e6ecf6a56f, 0x3cc355ccb90a71e2}}, - {{0xe9b69443903e9131, 0xb8a494cb7a5637ce, 0xc87cd1a4baba9244, 0x631eaf426bae7568}}}, -{{{0xb3e90410da66fe9f, 0x85dd4b526c16e5a6, 0xbc3d97611ef9bf83, 0x5599648b1ea919b5}}, - {{0x47d975b9a3700de8, 0x7280c5fbe2f80552, 0x53658f2732e45de1, 0x431f2c7f665f80b5}}, - {{0xd6026344858f7b19, 0x14ab352fa1ea514a, 0x8900441a2090a9d7, 0x7b04715f91253b26}}}, -{{{0x83edbd28acf6ae43, 0x86357c8b7d5c7ab4, 0xc0404769b7eb2c44, 0x59b37bf5c2f6583f}}, - {{0xb376c280c4e6bac6, 0x970ed3dd6d1d9b0b, 0xb09a9558450bf944, 0x48d0acfa57cde223}}, - {{0xb60f26e47dabe671, 0xf1d1a197622f3a37, 0x4208ce7ee9960394, 0x16234191336d3bdb}}}, -{{{0xb9e499def6267ff6, 0x7772ca7b742c0843, 0x23a0153fe9a4f2b1, 0x2cdfdfecd5d05006}}, - {{0xdd499cd61ff38640, 0x29cd9bc3063625a0, 0x51e2d8023dd73dc3, 0x4a25707a203b9231}}, - {{0x2ab7668a53f6ed6a, 0x304242581dd170a1, 0x4000144c3ae20161, 0x5721896d248e49fc}}}, -{{{0x0b6e5517fd181bae, 0x9022629f2bb963b4, 0x5509bce932064625, 0x578edd74f63c13da}}, - {{0x285d5091a1d0da4e, 0x4baa6fa7b5fe3e08, 0x63e5177ce19393b3, 0x03c935afc4b030fd}}, - {{0x997276c6492b0c3d, 0x47ccc2c4dfe205fc, 0xdcd29b84dd623a3c, 0x3ec2ab590288c7a2}}}, -{{{0xa1a0d27be4d87bb9, 0xa98b4deb61391aed, 0x99a0ddd073cb9b83, 0x2dd5c25a200fcace}}, - {{0xa7213a09ae32d1cb, 0x0f2b87df40f5c2d5, 0x0baea4c6e81eab29, 0x0e1bf66c6adbac5e}}, - {{0xe2abd5e9792c887e, 0x1a020018cb926d5d, 0xbfba69cdbaae5f1e, 0x730548b35ae88f5f}}}, -{{{0xc43551a3cba8b8ee, 0x65a26f1db2115f16, 0x760f4f52ab8c3850, 0x3043443b411db8ca}}, - {{0x805b094ba1d6e334, 0xbf3ef17709353f19, 0x423f06cb0622702b, 0x585a2277d87845dd}}, - {{0xa18a5f8233d48962, 0x6698c4b5ec78257f, 0xa78e6fa5373e41ff, 0x7656278950ef981f}}}, -{{{0x38c3cf59d51fc8c0, 0x9bedd2fd0506b6f2, 0x26bf109fab570e8f, 0x3f4160a8c1b846a6}}, - {{0xe17073a3ea86cf9d, 0x3a8cfbb707155fdc, 0x4853e7fc31838a8e, 0x28bbf484b613f616}}, - {{0xf2612f5c6f136c7c, 0xafead107f6dd11be, 0x527e9ad213de6f33, 0x1e79cb358188f75d}}}, -{{{0x013436c3eef7e3f1, 0x828b6a7ffe9e10f8, 0x7ff908e5bcf9defc, 0x65d7951b3a3b3831}}, - {{0x77e953d8f5e08181, 0x84a50c44299dded9, 0xdc6c2d0c864525e5, 0x478ab52d39d1f2f4}}, - {{0x66a6a4d39252d159, 0xe5dde1bc871ac807, 0xb82c6b40a6c1c96f, 0x16d87a411a212214}}}, -{{{0xb3bd7e5a42066215, 0x879be3cd0c5a24c1, 0x57c05db1d6f994b7, 0x28f87c8165f38ca6}}, - {{0xfba4d5e2d54e0583, 0xe21fafd72ebd99fa, 0x497ac2736ee9778f, 0x1f990b577a5a6dde}}, - {{0xa3344ead1be8f7d6, 0x7d1e50ebacea798f, 0x77c6569e520de052, 0x45882fe1534d6d3e}}}, -{{{0x6669345d757983d6, 0x62b6ed1117aa11a6, 0x7ddd1857985e128f, 0x688fe5b8f626f6dd}}, - {{0xd8ac9929943c6fe4, 0xb5f9f161a38392a2, 0x2699db13bec89af3, 0x7dcf843ce405f074}}, - {{0x6c90d6484a4732c0, 0xd52143fdca563299, 0xb3be28c3915dc6e1, 0x6739687e7327191b}}}, -{{{0xef782014385675a6, 0xa2649f30aafda9e8, 0x4cd1eb505cdfa8cb, 0x46115aba1d4dc0b3}}, - {{0xa66dcc9dc80c1ac0, 0x97a05cf41b38a436, 0xa7ebf3be95dbd7c6, 0x7da0b8f68d7e7dab}}, - {{0xd40f1953c3b5da76, 0x1dac6f7321119e9b, 0x03cc6021feb25960, 0x5a5f887e83674b4b}}}, -{{{0x8f6301cf70a13d11, 0xcfceb815350dd0c4, 0xf70297d4a4bca47e, 0x3669b656e44d1434}}, - {{0x9e9628d3a0a643b9, 0xb5c3cb00e6c32064, 0x9b5302897c2dec32, 0x43e37ae2d5d1c70c}}, - {{0x387e3f06eda6e133, 0x67301d5199a13ac0, 0xbd5ad8f836263811, 0x6a21e6cd4fd5e9be}}}, -{{{0xf1c6170a3046e65f, 0x58712a2a00d23524, 0x69dbbd3c8c82b755, 0x586bf9f1a195ff57}}, - {{0xef4129126699b2e3, 0x71d30847708d1301, 0x325432d01182b0bd, 0x45371b07001e8b36}}, - {{0xa6db088d5ef8790b, 0x5278f0dc610937e5, 0xac0349d261a16eb8, 0x0eafb03790e52179}}}, -{{{0x960555c13748042f, 0x219a41e6820baa11, 0x1c81f73873486d0c, 0x309acc675a02c661}}, - {{0x5140805e0f75ae1d, 0xec02fbe32662cc30, 0x2cebdf1eea92396d, 0x44ae3344c5435bb3}}, - {{0x9cf289b9bba543ee, 0xf3760e9d5ac97142, 0x1d82e5c64f9360aa, 0x62d5221b7f94678f}}}, -{{{0x524c299c18d0936d, 0xc86bb56c8a0c1a0c, 0xa375052edb4a8631, 0x5c0efde4bc754562}}, - {{0x7585d4263af77a3c, 0xdfae7b11fee9144d, 0xa506708059f7193d, 0x14f29a5383922037}}, - {{0xdf717edc25b2d7f5, 0x21f970db99b53040, 0xda9234b7c3ed4c62, 0x5e72365c7bee093e}}}, -{{{0x575bfc074571217f, 0x3779675d0694d95b, 0x9a0a37bbf4191e33, 0x77f1104c47b4eabc}}, - {{0x7d9339062f08b33e, 0x5b9659e5df9f32be, 0xacff3dad1f9ebdfd, 0x70b20555cb7349b7}}, - {{0xbe5113c555112c4c, 0x6688423a9a881fcd, 0x446677855e503b47, 0x0e34398f4a06404a}}}, -{{{0xb67d22d93ecebde8, 0x09b3e84127822f07, 0x743fa61fb05b6d8d, 0x5e5405368a362372}}, - {{0x18930b093e4b1928, 0x7de3e10e73f3f640, 0xf43217da73395d6f, 0x6f8aded6ca379c3e}}, - {{0xe340123dfdb7b29a, 0x487b97e1a21ab291, 0xf9967d02fde6949e, 0x780de72ec8d3de97}}}, -{{{0x0ae28545089ae7bc, 0x388ddecf1c7f4d06, 0x38ac15510a4811b8, 0x0eb28bf671928ce4}}, - {{0x671feaf300f42772, 0x8f72eb2a2a8c41aa, 0x29a17fd797373292, 0x1defc6ad32b587a6}}, - {{0xaf5bbe1aef5195a7, 0x148c1277917b15ed, 0x2991f7fb7ae5da2e, 0x467d201bf8dd2867}}}, -{{{0x95fe919a74ef4fad, 0x3a827becf6a308a2, 0x964e01d309a47b01, 0x71c43c4f5ba3c797}}, - {{0xbc1ef4bd567ae7a9, 0x3f624cb2d64498bd, 0xe41064d22c1f4ec8, 0x2ef9c5a5ba384001}}, - {{0xb6fd6df6fa9e74cd, 0xf18278bce4af267a, 0x8255b3d0f1ef990e, 0x5a758ca390c5f293}}}, -{{{0xa2b72710d9462495, 0x3aa8c6d2d57d5003, 0xe3d400bfa0b487ca, 0x2dbae244b3eb72ec}}, - {{0x8ce0918b1d61dc94, 0x8ded36469a813066, 0xd4e6a829afe8aad3, 0x0a738027f639d43f}}, - {{0x980f4a2f57ffe1cc, 0x00670d0de1839843, 0x105c3f4a49fb15fd, 0x2698ca635126a69c}}}, -{{{0xe765318832b0ba78, 0x381831f7925cff8b, 0x08a81b91a0291fcc, 0x1fb43dcc49caeb07}}, - {{0x2e3d702f5e3dd90e, 0x9e3f0918e4d25386, 0x5e773ef6024da96a, 0x3c004b0c4afa3332}}, - {{0x9aa946ac06f4b82b, 0x1ca284a5a806c4f3, 0x3ed3265fc6cd4787, 0x6b43fd01cd1fd217}}}, -{{{0xc7a75d4b4697c544, 0x15fdf848df0fffbf, 0x2868b9ebaa46785a, 0x5a68d7105b52f714}}, - {{0xb5c742583e760ef3, 0x75dc52b9ee0ab990, 0xbf1427c2072b923f, 0x73420b2d6ff0d9f0}}, - {{0xaf2cf6cb9e851e06, 0x8f593913c62238c4, 0xda8ab89699fbf373, 0x3db5632fea34bc9e}}}, -{{{0xf46eee2bf75dd9d8, 0x0d17b1f6396759a5, 0x1bf2d131499e7273, 0x04321adf49d75f13}}, - {{0x2e4990b1829825d5, 0xedeaeb873e9a8991, 0xeef03d394c704af8, 0x59197ea495df2b0e}}, - {{0x04e16019e4e55aae, 0xe77b437a7e2f92e9, 0xc7ce2dc16f159aa4, 0x45eafdc1f4d70cc0}}}, -{{{0x698401858045d72b, 0x4c22faa2cf2f0651, 0x941a36656b222dc6, 0x5a5eebc80362dade}}, - {{0xb60e4624cfccb1ed, 0x59dbc292bd5c0395, 0x31a09d1ddc0481c9, 0x3f73ceea5d56d940}}, - {{0xb7a7bfd10a4e8dc6, 0xbe57007e44c9b339, 0x60c1207f1557aefa, 0x26058891266218db}}}, -{{{0x59f704a68360ff04, 0xc3d93fde7661e6f4, 0x831b2a7312873551, 0x54ad0c2e4e615d57}}, - {{0x4c818e3cc676e542, 0x5e422c9303ceccad, 0xec07cccab4129f08, 0x0dedfa10b24443b8}}, - {{0xee3b67d5b82b522a, 0x36f163469fa5c1eb, 0xa5b4d2f26ec19fd3, 0x62ecb2baa77a9408}}}, -{{{0xe5ed795261152b3d, 0x4962357d0eddd7d1, 0x7482c8d0b96b4c71, 0x2e59f919a966d8be}}, - {{0x92072836afb62874, 0x5fcd5e8579e104a5, 0x5aad01adc630a14a, 0x61913d5075663f98}}, - {{0x0dc62d361a3231da, 0xfa47583294200270, 0x02d801513f9594ce, 0x3ddbc2a131c05d5c}}}, -{{{0x9adc0ff9ce5ec54b, 0x039c2a6b8c2f130d, 0x028007c7f0f89515, 0x78968314ac04b36b}}, - {{0xf3aa57a22796bb14, 0x883abab79b07da21, 0xe54be21831a0391c, 0x5ee7fb38d83205f9}}, - {{0x538dfdcb41446a8e, 0xa5acfda9434937f9, 0x46af908d263c8c78, 0x61d0633c9bca0d09}}}, -{{{0x63744935ffdb2566, 0xc5bd6b89780b68bb, 0x6f1b3280553eec03, 0x6e965fd847aed7f5}}, - {{0xada328bcf8fc73df, 0xee84695da6f037fc, 0x637fb4db38c2a909, 0x5b23ac2df8067bdc}}, - {{0x9ad2b953ee80527b, 0xe88f19aafade6d8d, 0x0e711704150e82cf, 0x79b9bbb9dd95dedc}}}, -{{{0xebb355406a3126c2, 0xd26383a868c8c393, 0x6c0c6429e5b97a82, 0x5065f158c9fd2147}}, - {{0xd1997dae8e9f7374, 0xa032a2f8cfbb0816, 0xcd6cba126d445f0a, 0x1ba811460accb834}}, - {{0x708169fb0c429954, 0xe14600acd76ecf67, 0x2eaab98a70e645ba, 0x3981f39e58a4faf2}}}, -{{{0x18fb8a7559230a93, 0x1d168f6960e6f45d, 0x3a85a94514a93cb5, 0x38dc083705acd0fd}}, - {{0xc845dfa56de66fde, 0xe152a5002c40483a, 0xe9d2e163c7b4f632, 0x30f4452edcbc1b65}}, - {{0x856d2782c5759740, 0xfa134569f99cbecc, 0x8844fc73c0ea4e71, 0x632d9a1a593f2469}}}, -{{{0xf6bb6b15b807cba6, 0x1823c7dfbc54f0d7, 0xbb1d97036e29670b, 0x0b24f48847ed4a57}}, - {{0xbf09fd11ed0c84a7, 0x63f071810d9f693a, 0x21908c2d57cf8779, 0x3a5a7df28af64ba2}}, - {{0xdcdad4be511beac7, 0xa4538075ed26ccf2, 0xe19cff9f005f9a65, 0x34fcf74475481f63}}}, -{{{0xc197e04c789767ca, 0xb8714dcb38d9467d, 0x55de888283f95fa8, 0x3d3bdc164dfa63f7}}, - {{0xa5bb1dab78cfaa98, 0x5ceda267190b72f2, 0x9309c9110a92608e, 0x0119a3042fb374b0}}, - {{0x67a2d89ce8c2177d, 0x669da5f66895d0c1, 0xf56598e5b282a2b0, 0x56c088f1ede20a73}}}, -{{{0x336d3d1110a86e17, 0xd7f388320b75b2fa, 0xf915337625072988, 0x09674c6b99108b87}}, - {{0x581b5fac24f38f02, 0xa90be9febae30cbd, 0x9a2169028acf92f0, 0x038b7ea48359038f}}, - {{0x9f4ef82199316ff8, 0x2f49d282eaa78d4f, 0x0971a5ab5aef3174, 0x6e5e31025969eb65}}}, -{{{0xb16c62f587e593fb, 0x4999eddeca5d3e71, 0xb491c1e014cc3e6d, 0x08f5114789a8dba8}}, - {{0x3304fb0e63066222, 0xfb35068987acba3f, 0xbd1924778c1061a3, 0x3058ad43d1838620}}, - {{0x323c0ffde57663d0, 0x05c3df38a22ea610, 0xbdc78abdac994f9a, 0x26549fa4efe3dc99}}}, -{{{0x741d5a461e6bf9d6, 0x2305b3fc7777a581, 0xd45574a26474d3d9, 0x1926e1dc6401e0ff}}, - {{0xdb468549af3f666e, 0xd77fcf04f14a0ea5, 0x3df23ff7a4ba0c47, 0x3a10dfe132ce3c85}}, - {{0xe07f4e8aea17cea0, 0x2fd515463a1fc1fd, 0x175322fd31f2c0f1, 0x1fa1d01d861e5d15}}}, -{{{0xcc8055947d599832, 0x1e4656da37f15520, 0x99f6f7744e059320, 0x773563bc6a75cf33}}, - {{0x38dcac00d1df94ab, 0x2e712bddd1080de9, 0x7f13e93efdd5e262, 0x73fced18ee9a01e5}}, - {{0x06b1e90863139cb3, 0xa493da67c5a03ecd, 0x8d77cec8ad638932, 0x1f426b701b864f44}}}, -{{{0xefc9264c41911c01, 0xf1a3b7b817a22c25, 0x5875da6bf30f1447, 0x4e1af5271d31b090}}, - {{0xf17e35c891a12552, 0xb76b8153575e9c76, 0xfa83406f0d9b723e, 0x0b76bb1b3fa7e438}}, - {{0x08b8c1f97f92939b, 0xbe6771cbd444ab6e, 0x22e5646399bb8017, 0x7b6dd61eb772a955}}}, -{{{0xb7adc1e850f33d92, 0x7998fa4f608cd5cf, 0xad962dbd8dfc5bdb, 0x703e9bceaf1d2f4f}}, - {{0x5730abf9ab01d2c7, 0x16fb76dc40143b18, 0x866cbe65a0cbb281, 0x53fa9b659bff6afe}}, - {{0x6c14c8e994885455, 0x843a5d6665aed4e5, 0x181bb73ebcd65af1, 0x398d93e5c4c61f50}}}, -{{{0x1c4bd16733e248f3, 0xbd9e128715bf0a5f, 0xd43f8cf0a10b0376, 0x53b09b5ddf191b13}}, - {{0xc3877c60d2e7e3f2, 0x3b34aaa030828bb1, 0x283e26e7739ef138, 0x699c9c9002c30577}}, - {{0xf306a7235946f1cc, 0x921718b5cce5d97d, 0x28cdd24781b4e975, 0x51caf30c6fcdd907}}}, -{{{0xa60ba7427674e00a, 0x630e8570a17a7bf3, 0x3758563dcf3324cc, 0x5504aa292383fdaa}}, - {{0x737af99a18ac54c7, 0x903378dcc51cb30f, 0x2b89bc334ce10cc7, 0x12ae29c189f8e99a}}, - {{0xa99ec0cb1f0d01cf, 0x0dd1efcc3a34f7ae, 0x55ca7521d09c4e22, 0x5fd14fe958eba5ea}}}, -{{{0xb5dc2ddf2845ab2c, 0x069491b10a7fe993, 0x4daaf3d64002e346, 0x093ff26e586474d1}}, - {{0x3c42fe5ebf93cb8e, 0xbedfa85136d4565f, 0xe0f0859e884220e8, 0x7dd73f960725d128}}, - {{0xb10d24fe68059829, 0x75730672dbaf23e5, 0x1367253ab457ac29, 0x2f59bcbc86b470a4}}}, -{{{0x83847d429917135f, 0xad1b911f567d03d7, 0x7e7748d9be77aad1, 0x5458b42e2e51af4a}}, - {{0x7041d560b691c301, 0x85201b3fadd7e71e, 0x16c2e16311335585, 0x2aa55e3d010828b1}}, - {{0xed5192e60c07444f, 0x42c54e2d74421d10, 0x352b4c82fdb5c864, 0x13e9004a8a768664}}}, -{{{0x739d8845832fcedb, 0xfa38d6c9ae6bf863, 0x32bc0dcab74ffef7, 0x73937e8814bce45e}}, - {{0xbb2e00c9193b877f, 0xece3a890e0dc506b, 0xecf3b7c036de649f, 0x5f46040898de9e1a}}, - {{0xb9037116297bf48d, 0xa9d13b22d4f06834, 0xe19715574696bdc6, 0x2cf8a4e891d5e835}}}, -{{{0x6d93fd8707110f67, 0xdd4c09d37c38b549, 0x7cb16a4cc2736a86, 0x2049bd6e58252a09}}, - {{0x2cb5487e17d06ba2, 0x24d2381c3950196b, 0xd7659c8185978a30, 0x7a6f7f2891d6a4f6}}, - {{0x7d09fd8d6a9aef49, 0xf0ee60be5b3db90b, 0x4c21b52c519ebfd4, 0x6011aadfc545941d}}}, -{{{0x5f67926dcf95f83c, 0x7c7e856171289071, 0xd6a1e7f3998f7a5b, 0x6fc5cc1b0b62f9e0}}, - {{0x63ded0c802cbf890, 0xfbd098ca0dff6aaa, 0x624d0afdb9b6ed99, 0x69ce18b779340b1e}}, - {{0xd1ef5528b29879cb, 0xdd1aae3cd47e9092, 0x127e0442189f2352, 0x15596b3ae57101f1}}}, -{{{0x462739d23f9179a2, 0xff83123197d6ddcf, 0x1307deb553f2148a, 0x0d2237687b5f4dda}}, - {{0x09ff31167e5124ca, 0x0be4158bd9c745df, 0x292b7d227ef556e5, 0x3aa4e241afb6d138}}, - {{0x2cc138bf2a3305f5, 0x48583f8fa2e926c3, 0x083ab1a25549d2eb, 0x32fcaa6e4687a36c}}}, -{{{0x7bc56e8dc57d9af5, 0x3e0bd2ed9df0bdf2, 0xaac014de22efe4a3, 0x4627e9cefebd6a5c}}, - {{0x3207a4732787ccdf, 0x17e31908f213e3f8, 0xd5b2ecd7f60d964e, 0x746f6336c2600be9}}, - {{0x3f4af345ab6c971c, 0xe288eb729943731f, 0x33596a8a0344186d, 0x7b4917007ed66293}}}, -{{{0x2d85fb5cab84b064, 0x497810d289f3bc14, 0x476adc447b15ce0c, 0x122ba376f844fd7b}}, - {{0x54341b28dd53a2dd, 0xaa17905bdf42fc3f, 0x0ff592d94dd2f8f4, 0x1d03620fe08cd37d}}, - {{0xc20232cda2b4e554, 0x9ed0fd42115d187f, 0x2eabb4be7dd479d9, 0x02c70bf52b68ec4c}}}, -{{{0xa287ec4b5d0b2fbb, 0x415c5790074882ca, 0xe044a61ec1d0815c, 0x26334f0a409ef5e0}}, - {{0xace532bf458d72e1, 0x5be768e07cb73cb5, 0x56cf7d94ee8bbde7, 0x6b0697e3feb43a03}}, - {{0xb6c8f04adf62a3c0, 0x3ef000ef076da45d, 0x9c9cb95849f0d2a9, 0x1cc37f43441b2fae}}}, -{{{0x508f565a5cc7324f, 0xd061c4c0e506a922, 0xfb18abdb5c45ac19, 0x6c6809c10380314a}}, - {{0xd76656f1c9ceaeb9, 0x1c5b15f818e5656a, 0x26e72832844c2334, 0x3a346f772f196838}}, - {{0xd2d55112e2da6ac8, 0xe9bd0331b1e851ed, 0x960746dd8ec67262, 0x05911b9f6ef7c5d0}}}, -{{{0xc1339983f5df0ebb, 0xc0f3758f512c4cac, 0x2cf1130a0bb398e1, 0x6b3cecf9aa270c62}}, - {{0x5349acf3512eeaef, 0x20c141d31cc1cb49, 0x24180c07a99a688d, 0x555ef9d1c64b2d17}}, - {{0x36a770ba3b73bd08, 0x624aef08a3afbf0c, 0x5737ff98b40946f2, 0x675f4de13381749d}}}, -{{{0x0e2c52036b1782fc, 0x64816c816cad83b4, 0xd0dcbdd96964073e, 0x13d99df70164c520}}, - {{0xa12ff6d93bdab31d, 0x0725d80f9d652dfe, 0x019c4ff39abe9487, 0x60f450b882cd3c43}}, - {{0x014b5ec321e5c0ca, 0x4fcb69c9d719bfa2, 0x4e5f1c18750023a0, 0x1c06de9e55edac80}}}, -{{{0x990f7ad6a33ec4e2, 0x6608f938be2ee08e, 0x9ca143c563284515, 0x4cf38a1fec2db60d}}, - {{0xffd52b40ff6d69aa, 0x34530b18dc4049bb, 0x5e4a5c2fa34d9897, 0x78096f8e7d32ba2d}}, - {{0xa0aaaa650dfa5ce7, 0xf9c49e2a48b5478c, 0x4f09cc7d7003725b, 0x373cad3a26091abe}}}, -{{{0xb294634d82c9f57c, 0x1fcbfde124934536, 0x9e9c4db3418cdb5a, 0x0040f3d9454419fc}}, - {{0xf1bea8fb89ddbbad, 0x3bcb2cbc61aeaecb, 0x8f58a7bb1f9b8d9d, 0x21547eda5112a686}}, - {{0xdefde939fd5986d3, 0xf4272c89510a380c, 0xb72ba407bb3119b9, 0x63550a334a254df4}}}, -{{{0x6507d6edb569cf37, 0x178429b00ca52ee1, 0xea7c0090eb6bd65d, 0x3eea62c7daf78f51}}, - {{0x9bba584572547b49, 0xf305c6fae2c408e0, 0x60e8fa69c734f18d, 0x39a92bafaa7d767a}}, - {{0x9d24c713e693274e, 0x5f63857768dbd375, 0x70525560eb8ab39a, 0x68436a0665c9c4cd}}}, -{{{0xbc0235e8202f3f27, 0xc75c00e264f975b0, 0x91a4e9d5a38c2416, 0x17b6e7f68ab789f9}}, - {{0x1e56d317e820107c, 0xc5266844840ae965, 0xc1e0a1c6320ffc7a, 0x5373669c91611472}}, - {{0x5d2814ab9a0e5257, 0x908f2084c9cab3fc, 0xafcaf5885b2d1eca, 0x1cb4b5a678f87d11}}}, -{{{0xb664c06b394afc6c, 0x0c88de2498da5fb1, 0x4f8d03164bcad834, 0x330bca78de7434a2}}, - {{0x6b74aa62a2a007e7, 0xf311e0b0f071c7b1, 0x5707e438000be223, 0x2dc0fd2d82ef6eac}}, - {{0x982eff841119744e, 0xf9695e962b074724, 0xc58ac14fbfc953fb, 0x3c31be1b369f1cf5}}}, -{{{0xb0f4864d08948aee, 0x07dc19ee91ba1c6f, 0x7975cdaea6aca158, 0x330b61134262d4bb}}, - {{0xc168bc93f9cb4272, 0xaeb8711fc7cedb98, 0x7f0e52aa34ac8d7a, 0x41cec1097e7d55bb}}, - {{0xf79619d7a26d808a, 0xbb1fd49e1d9e156d, 0x73d7c36cdba1df27, 0x26b44cd91f28777d}}}, -{{{0x51f048478f387475, 0xb25dbcf49cbecb3c, 0x9aab1244d99f2055, 0x2c709e6c1c10a5d6}}, - {{0xe1b7f29362730383, 0x4b5279ffebca8a2c, 0xdafc778abfd41314, 0x7deb10149c72610f}}, - {{0xcb62af6a8766ee7a, 0x66cbec045553cd0e, 0x588001380f0be4b5, 0x08e68e9ff62ce2ea}}}, -{{{0x34ad500a4bc130ad, 0x8d38db493d0bd49c, 0xa25c3d98500a89be, 0x2f1f3f87eeba3b09}}, - {{0x2f2d09d50ab8f2f9, 0xacb9218dc55923df, 0x4a8f342673766cb9, 0x4cb13bd738f719f5}}, - {{0xf7848c75e515b64a, 0xa59501badb4a9038, 0xc20d313f3f751b50, 0x19a1e353c0ae2ee8}}}, -{{{0x7d1c7560bafa05c3, 0xb3e1a0a0c6e55e61, 0xe3529718c0d66473, 0x41546b11c20c3486}}, - {{0xb42172cdd596bdbd, 0x93e0454398eefc40, 0x9fb15347b44109b5, 0x736bd3990266ae34}}, - {{0x85532d509334b3b4, 0x46fd114b60816573, 0xcc5f5f30425c8375, 0x412295a2b87fab5c}}}, -{{{0x19c99b88f57ed6e9, 0x5393cb266df8c825, 0x5cee3213b30ad273, 0x14e153ebb52d2e34}}, - {{0x2e655261e293eac6, 0x845a92032133acdb, 0x460975cb7900996b, 0x0760bb8d195add80}}, - {{0x413e1a17cde6818a, 0x57156da9ed69a084, 0x2cbf268f46caccb1, 0x6b34be9bc33ac5f2}}}, -{{{0xf3df2f643a78c0b2, 0x4c3e971ef22e027c, 0xec7d1c5e49c1b5a3, 0x2012c18f0922dd2d}}, - {{0x11fc69656571f2d3, 0xc6c9e845530e737a, 0xe33ae7a2d4fe5035, 0x01b9c7b62e6dd30b}}, - {{0x880b55e55ac89d29, 0x1483241f45a0a763, 0x3d36efdfc2e76c1f, 0x08af5b784e4bade8}}}, -{{{0x283499dc881f2533, 0x9d0525da779323b6, 0x897addfb673441f4, 0x32b79d71163a168d}}, - {{0xe27314d289cc2c4b, 0x4be4bd11a287178d, 0x18d528d6fa3364ce, 0x6423c1d5afd9826e}}, - {{0xcc85f8d9edfcb36a, 0x22bcc28f3746e5f9, 0xe49de338f9e5d3cd, 0x480a5efbc13e2dcc}}}, -{{{0x0b51e70b01622071, 0x06b505cf8b1dafc5, 0x2c6bb061ef5aabcd, 0x47aa27600cb7bf31}}, - {{0xb6614ce442ce221f, 0x6e199dcc4c053928, 0x663fb4a4dc1cbe03, 0x24b31d47691c8e06}}, - {{0x2a541eedc015f8c3, 0x11a4fe7e7c693f7c, 0xf0af66134ea278d6, 0x545b585d14dda094}}}, -{{{0x67bf275ea0d43a0f, 0xade68e34089beebe, 0x4289134cd479e72e, 0x0f62f9c332ba5454}}, - {{0x6204e4d0e3b321e1, 0x3baa637a28ff1e95, 0x0b0ccffd5b99bd9e, 0x4d22dc3e64c8d071}}, - {{0xfcb46589d63b5f39, 0x5cae6a3f57cbcf61, 0xfebac2d2953afa05, 0x1c0fa01a36371436}}}, -{{{0xd2c604b622943dff, 0xbc8cbece44cfb3a0, 0x5d254ff397808678, 0x0fa3614f3b1ca6bf}}, - {{0x69082b0e8c936a50, 0xf9c9a035c1dac5b6, 0x6fb73e54c4dfb634, 0x4005419b1d2bc140}}, - {{0xa003febdb9be82f0, 0x2089c1af3a44ac90, 0xf8499f911954fa8e, 0x1fba218aef40ab42}}}, -{{{0xab549448fac8f53e, 0x81f6e89a7ba63741, 0x74fd6c7d6c2b5e01, 0x392e3acaa8c86e42}}, - {{0x4f3e57043e7b0194, 0xa81d3eee08daaf7f, 0xc839c6ab99dcdef1, 0x6c535d13ff7761d5}}, - {{0x4cbd34e93e8a35af, 0x2e0781445887e816, 0x19319c76f29ab0ab, 0x25e17fe4d50ac13b}}}, -{{{0x0a289bd71e04f676, 0x208e1c52d6420f95, 0x5186d8b034691fab, 0x255751442a9fb351}}, - {{0x915f7ff576f121a7, 0xc34a32272fcd87e3, 0xccba2fde4d1be526, 0x6bba828f8969899b}}, - {{0xe2d1bc6690fe3901, 0x4cb54a18a0997ad5, 0x971d6914af8460d4, 0x559d504f7f6b7be4}}}, -{{{0xa7738378b3eb54d5, 0x1d69d366a5553c7c, 0x0a26cf62f92800ba, 0x01ab12d5807e3217}}, - {{0x9c4891e7f6d266fd, 0x0744a19b0307781b, 0x88388f1d6061e23b, 0x123ea6a3354bd50e}}, - {{0x118d189041e32d96, 0xb9ede3c2d8315848, 0x1eab4271d83245d9, 0x4a3961e2c918a154}}}, -{{{0x71dc3be0f8e6bba0, 0xd6cef8347effe30a, 0xa992425fe13a476a, 0x2cd6bce3fb1db763}}, - {{0x0327d644f3233f1e, 0x499a260e34fcf016, 0x83b5a716f2dab979, 0x68aceead9bd4111f}}, - {{0x38b4c90ef3d7c210, 0x308e6e24b7ad040c, 0x3860d9f1b7e73e23, 0x595760d5b508f597}}}, -{{{0x6129bfe104aa6397, 0x8f960008a4a7fccb, 0x3f8bc0897d909458, 0x709fa43edcb291a9}}, - {{0x882acbebfd022790, 0x89af3305c4115760, 0x65f492e37d3473f4, 0x2cb2c5df54515a2b}}, - {{0xeb0a5d8c63fd2aca, 0xd22bc1662e694eff, 0x2723f36ef8cbb03a, 0x70f029ecf0c8131f}}}, -{{{0x461307b32eed3e33, 0xae042f33a45581e7, 0xc94449d3195f0366, 0x0b7d5d8a6c314858}}, - {{0x2a6aafaa5e10b0b9, 0x78f0a370ef041aa9, 0x773efb77aa3ad61f, 0x44eca5a2a74bd9e1}}, - {{0x25d448327b95d543, 0x70d38300a3340f1d, 0xde1c531c60e1c52b, 0x272224512c7de9e4}}}, -{{{0x1abc92af49c5342e, 0xffeed811b2e6fad0, 0xefa28c8dfcc84e29, 0x11b5df18a44cc543}}, - {{0xbf7bbb8a42a975fc, 0x8c5c397796ada358, 0xe27fc76fcdedaa48, 0x19735fd7f6bc20a6}}, - {{0xe3ab90d042c84266, 0xeb848e0f7f19547e, 0x2503a1d065a497b9, 0x0fef911191df895f}}} \ No newline at end of file diff --git a/ext/ed25519-amd64-asm/ge25519_base_slide_multiples.data b/ext/ed25519-amd64-asm/ge25519_base_slide_multiples.data deleted file mode 100644 index 32a5d474..00000000 --- a/ext/ed25519-amd64-asm/ge25519_base_slide_multiples.data +++ /dev/null @@ -1,96 +0,0 @@ -{{{0x9d103905d740913e, 0xfd399f05d140beb3, 0xa5c18434688f8a09, 0x44fd2f9298f81267}}, - {{0x2fbc93c6f58c3b85, 0xcf932dc6fb8c0e19, 0x270b4898643d42c2, 0x07cf9d3a33d4ba65}}, - {{0xabc91205877aaa68, 0x26d9e823ccaac49e, 0x5a1b7dcbdd43598c, 0x6f117b689f0c65a8}}}, -{{{0x56611fe8a4fcd265, 0x3bd353fde5c1ba7d, 0x8131f31a214bd6bd, 0x2ab91587555bda62}}, - {{0xaf25b0a84cee9730, 0x025a8430e8864b8a, 0xc11b50029f016732, 0x7a164e1b9a80f8f4}}, - {{0x14ae933f0dd0d889, 0x589423221c35da62, 0xd170e5458cf2db4c, 0x5a2826af12b9b4c6}}}, -{{{0x7f9182c3a447d6ba, 0xd50014d14b2729b7, 0xe33cf11cb864a087, 0x154a7e73eb1b55f3}}, - {{0xa212bc4408a5bb33, 0x8d5048c3c75eed02, 0xdd1beb0c5abfec44, 0x2945ccf146e206eb}}, - {{0xbcbbdbf1812a8285, 0x270e0807d0bdd1fc, 0xb41b670b1bbda72d, 0x43aabe696b3bb69a}}}, -{{{0xba6f2c9aaa3221b1, 0x6ca021533bba23a7, 0x9dea764f92192c3a, 0x1d6edd5d2e5317e0}}, - {{0x6b1a5cd0944ea3bf, 0x7470353ab39dc0d2, 0x71b2528228542e49, 0x461bea69283c927e}}, - {{0xf1836dc801b8b3a2, 0xb3035f47053ea49a, 0x529c41ba5877adf3, 0x7a9fbb1c6a0f90a7}}}, -{{{0xf36e217e039d8064, 0x98a081b6f520419b, 0x96cbc608e75eb044, 0x49c05a51fadc9c8f}}, - {{0x9b2e678aa6a8632f, 0xa6509e6f51bc46c5, 0xceb233c9c686f5b5, 0x34b9ed338add7f59}}, - {{0x06b4e8bf9045af1b, 0xe2ff83e8a719d22f, 0xaaf6fc2993d4cf16, 0x73c172021b008b06}}}, -{{{0x315f5b0249864348, 0x3ed6b36977088381, 0xa3a075556a8deb95, 0x18ab598029d5c77f}}, - {{0x2fbf00848a802ade, 0xe5d9fecf02302e27, 0x113e847117703406, 0x4275aae2546d8faf}}, - {{0xd82b2cc5fd6089e9, 0x031eb4a13282e4a4, 0x44311199b51a8622, 0x3dc65522b53df948}}}, -{{{0x506f013b327fbf93, 0xaefcebc99b776f6b, 0x9d12b232aaad5968, 0x0267882d176024a7}}, - {{0xbf70c222a2007f6d, 0xbf84b39ab5bcdedb, 0x537a0e12fb07ba07, 0x234fd7eec346f241}}, - {{0x5360a119732ea378, 0x2437e6b1df8dd471, 0xa2ef37f891a7e533, 0x497ba6fdaa097863}}}, -{{{0x040bcd86468ccf0b, 0xd3829ba42a9910d6, 0x7508300807b25192, 0x43b5cd4218d05ebf}}, - {{0x24cecc0313cfeaa0, 0x8648c28d189c246d, 0x2dbdbdfac1f2d4d0, 0x61e22917f12de72b}}, - {{0x5d9a762f9bd0b516, 0xeb38af4e373fdeee, 0x032e5a7d93d64270, 0x511d61210ae4d842}}}, -{{{0x081386484420de87, 0x8a1cf016b592edb4, 0x39fa4e2729942d25, 0x71a7fe6fe2482810}}, - {{0x92c676ef950e9d81, 0xa54620cdc0d7044f, 0xaa9b36646f8f1248, 0x6d325924ddb855e3}}, - {{0x6c7182b8a5c8c854, 0x33fd1479fe5f2a03, 0x72cf591883778d0c, 0x4746c4b6559eeaa9}}}, -{{{0x348546c864741147, 0x7d35aedd0efcc849, 0xff939a760672a332, 0x219663497db5e6d6}}, - {{0xd3777b3c6dc69a2b, 0xdefab2276f89f617, 0x45651cf7b53a16b5, 0x5c9a51de34fe9fb7}}, - {{0xf510f1cf79f10e67, 0xffdddaa1e658515b, 0x09c3a71710142277, 0x4804503c608223bb}}}, -{{{0x3b6821d23a36d175, 0xbbb40aa7e99b9e32, 0x5d9e5ce420838a47, 0x771e098858de4c5e}}, - {{0xc4249ed02ca37fc7, 0xa059a0e3a615acab, 0x88a96ed7c96e0e23, 0x553398a51650696d}}, - {{0x9a12f5d278451edf, 0x3ada5d7985899ccb, 0x477f4a2d9fa59508, 0x5a5ed1d68ff5a611}}}, -{{{0xbae5e0c558527359, 0x392e5c19cadb9d7e, 0x28653c1eda1cabe9, 0x019b60135fefdc44}}, - {{0x1195122afe150e83, 0xcf209a257e4b35d8, 0x7387f8291e711e20, 0x44acb897d8bf92f0}}, - {{0x1e6068145e134b83, 0xc4f5e64f24304c16, 0x506e88a8fc1a3ed7, 0x150c49fde6ad2f92}}}, -{{{0xb849863c9cdca868, 0xc83f44dbb8714ad0, 0xfe3ee3560c36168d, 0x78a6d7791e05fbc1}}, - {{0x8e7bf29509471138, 0x5d6fef394f75a651, 0x10af79c425a708ad, 0x6b2b5a075bb99922}}, - {{0x58bf704b47a0b976, 0xa601b355741748d5, 0xaa2b1fb1d542f590, 0x725c7ffc4ad55d00}}}, -{{{0x91802bf71cd098c0, 0xfe416ca4ed5e6366, 0xdf585d714902994c, 0x4cd54625f855fae7}}, - {{0xe4426715d1cf99b2, 0x7352d51102a20d34, 0x23d1157b8b12109f, 0x794cc9277cb1f3a3}}, - {{0x4af6c426c2ac5053, 0xbc9aedad32f67258, 0x2ad032f10a311021, 0x7008357b6fcc8e85}}}, -{{{0xd01b9fbb82584a34, 0x47ab6463d2b4792b, 0xb631639c48536202, 0x13a92a3669d6d428}}, - {{0x0b88672738773f01, 0xb8ccc8fa95fbccfb, 0x8d2dd5a3b9ad29b6, 0x06ef7e9851ad0f6a}}, - {{0xca93771cc0577de5, 0x7540e41e5035dc5c, 0x24680f01d802e071, 0x3c296ddf8a2af86a}}}, -{{{0xfceb4d2ebb1f2541, 0xb89510c740adb91f, 0xfc71a37dd0a1ad05, 0x0a892c700747717b}}, - {{0xaead15f9d914a713, 0xa92f7bf98c8ff912, 0xaff823179f53d730, 0x7a99d393490c77ba}}, - {{0x8f52ed2436bda3e8, 0x77a8c84157e80794, 0xa5a96563262f9ce0, 0x286762d28302f7d2}}}, -{{{0x7c558e2bce2ef5bd, 0xe4986cb46747bc63, 0x154a179f3bbb89b8, 0x7686f2a3d6f1767a}}, - {{0x4e7836093ce35b25, 0x82e1181db26baa97, 0x0cc192d3cbc7b83f, 0x32f1da046a9d9d3a}}, - {{0xaa8d12a66d597c6a, 0x8f11930304d3852b, 0x3f91dc73c209b022, 0x561305f8a9ad28a6}}}, -{{{0x6722cc28e7b0c0d5, 0x709de9bbdb075c53, 0xcaf68da7d7010a61, 0x030a1aef2c57cc6c}}, - {{0x100c978dec92aed1, 0xca43d5434d6d73e5, 0x83131b22d847ba48, 0x00aaec53e35d4d2c}}, - {{0x7bb1f773003ad2aa, 0x0b3f29802b216608, 0x7821dc86520ed23e, 0x20be9c1c24065480}}}, -{{{0x20e0e44ae2025e60, 0xb03b3b2fcbdcb938, 0x105d639cf95a0d1c, 0x69764c545067e311}}, - {{0xe15387d8249673a6, 0x5943bc2df546e493, 0x1c7f9a81c36f63b5, 0x750ab3361f0ac1de}}, - {{0x1e8a3283a2f81037, 0x6f2eda23bd7fcbf1, 0xb72fd15bac2e2563, 0x54f96b3fb7075040}}}, -{{{0x177dafc616b11ecd, 0x89764b9cfa576479, 0xb7a8a110e6ece785, 0x78e6839fbe85dbf0}}, - {{0x0fadf20429669279, 0x3adda2047d7d724a, 0x6f3d94828c5760f1, 0x3d7fe9c52bb7539e}}, - {{0x70332df737b8856b, 0x75d05d43041a178a, 0x320ff74aa0e59e22, 0x70f268f350088242}}}, -{{{0x2324112070dcf355, 0x380cc97ee7fce117, 0xb31ddeed3552b698, 0x404e56c039b8c4b9}}, - {{0x66864583b1805f47, 0xf535c5d160dd7c19, 0xe9874eb71e4cb006, 0x7c0d345cfad889d9}}, - {{0x591f1f4b8c78338a, 0xa0366ab167e0b5e1, 0x5cbc4152b45f3d44, 0x20d754762aaec777}}}, -{{{0x9d74feb135b9f543, 0x84b37df1de8c956c, 0xe9322b0757138ba9, 0x38b8ada8790b4ce1}}, - {{0x5e8fc36fc73bb758, 0xace543a5363cbb9a, 0xa9934a7d903bc922, 0x2b8f1e46f3ceec62}}, - {{0xb5c04a9cdf51f95d, 0x2b3952aecb1fdeac, 0x1d106d8b328b66da, 0x049aeb32ceba1953}}}, -{{{0xd7767d3c63dcfe7e, 0x209c594897856e40, 0xb6676861e14f7c13, 0x51c665e0c8d625fc}}, - {{0xaa507d0b75fc7931, 0x0fef924b7a6725d3, 0x1d82542b396b3930, 0x795ee17530f674fc}}, - {{0x254a5b0a52ecbd81, 0x5d411f6ee034afe7, 0xe6a24d0dcaee4a31, 0x6cd19bf49dc54477}}}, -{{{0x7e87619052179ca3, 0x571d0a060b2c9f85, 0x80a2baa88499711e, 0x7520f3db40b2e638}}, - {{0x1ffe612165afc386, 0x082a2a88b8d51b10, 0x76f6627e20990baa, 0x5e01b3a7429e43e7}}, - {{0x3db50be3d39357a1, 0x967b6cdd599e94a5, 0x1a309a64df311e6e, 0x71092c9ccef3c986}}}, -{{{0x53d8523f0364918c, 0xa2b404f43fab6b1c, 0x080b4a9e6681e5a4, 0x0ea15b03d0257ba7}}, - {{0x856bd8ac74051dcf, 0x03f6a40855b7aa1e, 0x3a4ae7cbc9743ceb, 0x4173a5bb7137abde}}, - {{0x17c56e31f0f9218a, 0x5a696e2b1afc4708, 0xf7931668f4b2f176, 0x5fc565614a4e3a67}}}, -{{{0x136e570dc46d7ae5, 0x0fd0aacc54f8dc8f, 0x59549f03310dad86, 0x62711c414c454aa1}}, - {{0x4892e1e67790988e, 0x01d5950f1c5cd722, 0xe3b0819ae5923eed, 0x3214c7409d46651b}}, - {{0x1329827406651770, 0x3ba4a0668a279436, 0xd9b6b8ec185d223c, 0x5bea94073ecb833c}}}, -{{{0x641dbf0912c89be4, 0xacf38b317d6e579c, 0xabfe9e02f697b065, 0x3aacd5c148f61eec}}, - {{0xb470ce63f343d2f8, 0x0067ba8f0543e8f1, 0x35da51a1a2117b6f, 0x4ad0785944f1bd2f}}, - {{0x858e3b34c3318301, 0xdc99c04707316826, 0x34085b2ed39da88c, 0x3aff0cb1d902853d}}}, -{{{0x87c5c7eb3a20405e, 0x8ee311efedad56c9, 0x29252e48ad29d5f9, 0x110e7e86f4cd251d}}, - {{0x9226430bf4c53505, 0x68e49c13261f2283, 0x09ef33788fd327c6, 0x2ccf9f732bd99e7f}}, - {{0x57c0d89ed603f5e4, 0x12888628f0b0200c, 0x53172709a02e3bb7, 0x05c557e0b9693a37}}}, -{{{0xd8f9ce311fc97e6f, 0x7a3f263011f9fdae, 0xe15b7ea08bed25dd, 0x6e154c178fe9875a}}, - {{0xf776bbb089c20eb0, 0x61f85bf6fa0fd85c, 0xb6b93f4e634421fb, 0x289fef0841861205}}, - {{0xcf616336fed69abf, 0x9b16e4e78335c94f, 0x13789765753a7fe7, 0x6afbf642a95ca319}}}, -{{{0x7da8de0c62f5d2c1, 0x98fc3da4b00e7b9a, 0x7deb6ada0dad70e0, 0x0db4b851b95038c4}}, - {{0x5de55070f913a8cc, 0x7d1d167b2b0cf561, 0xda2956b690ead489, 0x12c093cedb801ed9}}, - {{0xfc147f9308b8190f, 0x06969da0a11ae310, 0xcee75572dac7d7fd, 0x33aa8799c6635ce6}}}, -{{{0xaf0ff51ebd085cf2, 0x78f51a8967d33f1f, 0x6ec2bfe15060033c, 0x233c6f29e8e21a86}}, - {{0x8348f588fc156cb1, 0x6da2ba9b1a0a6d27, 0xe2262d5c87ca5ab6, 0x212cd0c1c8d589a6}}, - {{0xd2f4d5107f18c781, 0x122ecdf2527e9d28, 0xa70a862a3d3d3341, 0x1db7778911914ce3}}}, -{{{0xddf352397c6bc26f, 0x7a97e2cc53d50113, 0x7c74f43abf79a330, 0x31ad97ad26e2adfc}}, - {{0xb3394769dd701ab6, 0xe2b8ded419cf8da5, 0x15df4161fd2ac852, 0x7ae2ca8a017d24be}}, - {{0xb7e817ed0920b962, 0x1e8518cc3f19da9d, 0xe491c14f25560a64, 0x1ed1fc53a6622c83}}} \ No newline at end of file diff --git a/ext/ed25519-amd64-asm/ge25519_dbl_p1p1.s b/ext/ed25519-amd64-asm/ge25519_dbl_p1p1.s deleted file mode 100644 index 265daf09..00000000 --- a/ext/ed25519-amd64-asm/ge25519_dbl_p1p1.s +++ /dev/null @@ -1,2975 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 pp - -# qhasm: input rp - -# qhasm: input pp - -# qhasm: int64 a0 - -# qhasm: int64 a1 - -# qhasm: int64 a2 - -# qhasm: int64 a3 - -# qhasm: stack64 a0_stack - -# qhasm: stack64 a1_stack - -# qhasm: stack64 a2_stack - -# qhasm: stack64 a3_stack - -# qhasm: int64 b0 - -# qhasm: int64 b1 - -# qhasm: int64 b2 - -# qhasm: int64 b3 - -# qhasm: stack64 b0_stack - -# qhasm: stack64 b1_stack - -# qhasm: stack64 b2_stack - -# qhasm: stack64 b3_stack - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: stack64 c0_stack - -# qhasm: stack64 c1_stack - -# qhasm: stack64 c2_stack - -# qhasm: stack64 c3_stack - -# qhasm: int64 d0 - -# qhasm: int64 d1 - -# qhasm: int64 d2 - -# qhasm: int64 d3 - -# qhasm: stack64 d0_stack - -# qhasm: stack64 d1_stack - -# qhasm: stack64 d2_stack - -# qhasm: stack64 d3_stack - -# qhasm: int64 e0 - -# qhasm: int64 e1 - -# qhasm: int64 e2 - -# qhasm: int64 e3 - -# qhasm: stack64 e0_stack - -# qhasm: stack64 e1_stack - -# qhasm: stack64 e2_stack - -# qhasm: stack64 e3_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: stack64 rx0_stack - -# qhasm: stack64 rx1_stack - -# qhasm: stack64 rx2_stack - -# qhasm: stack64 rx3_stack - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 ry4 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 rt0 - -# qhasm: int64 rt1 - -# qhasm: int64 rt2 - -# qhasm: int64 rt3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: int64 squarer4 - -# qhasm: int64 squarer5 - -# qhasm: int64 squarer6 - -# qhasm: int64 squarer7 - -# qhasm: int64 squarer8 - -# qhasm: int64 squarerax - -# qhasm: int64 squarerdx - -# qhasm: int64 squaret1 - -# qhasm: int64 squaret2 - -# qhasm: int64 squaret3 - -# qhasm: int64 squarec - -# qhasm: int64 squarezero - -# qhasm: int64 squarei38 - -# qhasm: int64 addt0 - -# qhasm: int64 addt1 - -# qhasm: int64 subt0 - -# qhasm: int64 subt1 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 -.globl crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1 -_crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1: -crypto_sign_ed25519_amd64_64_ge25519_dbl_p1p1: -mov %rsp,%r11 -and $31,%r11 -add $192,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarerax = *(uint64 *)(pp + 8) -# asm 1: movq 8(squarerax=int64#7 -# asm 2: movq 8(squarerax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) -# asm 1: mulq 0(a1=int64#5 -# asm 2: mov a1=%r8 -mov %rax,%r8 - -# qhasm: a2 = squarerdx -# asm 1: mov a2=int64#6 -# asm 2: mov a2=%r9 -mov %rdx,%r9 - -# qhasm: squarerax = *(uint64 *)(pp + 16) -# asm 1: movq 16(squarerax=int64#7 -# asm 2: movq 16(squarerax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 8) -# asm 1: mulq 8(a3=int64#8 -# asm 2: mov a3=%r10 -mov %rax,%r10 - -# qhasm: squarer4 = squarerdx -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rdx,%r11 - -# qhasm: squarerax = *(uint64 *)(pp + 24) -# asm 1: movq 24(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 16) -# asm 1: mulq 16(squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rax,%r12 - -# qhasm: squarer6 = squarerdx -# asm 1: mov squarer6=int64#11 -# asm 2: mov squarer6=%r13 -mov %rdx,%r13 - -# qhasm: squarerax = *(uint64 *)(pp + 16) -# asm 1: movq 16(squarerax=int64#7 -# asm 2: movq 16(squarerax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) -# asm 1: mulq 0(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 8) -# asm 1: mulq 8(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) -# asm 1: mulq 0(squarerax=int64#7 -# asm 2: movq 0(squarerax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 0) -# asm 1: mulq 0(a0=int64#12 -# asm 2: mov a0=%r14 -mov %rax,%r14 - -# qhasm: squaret1 = squarerdx -# asm 1: mov squaret1=int64#13 -# asm 2: mov squaret1=%r15 -mov %rdx,%r15 - -# qhasm: squarerax = *(uint64 *)(pp + 8) -# asm 1: movq 8(squarerax=int64#7 -# asm 2: movq 8(squarerax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 8) -# asm 1: mulq 8(squaret2=int64#14 -# asm 2: mov squaret2=%rbx -mov %rax,%rbx - -# qhasm: squaret3 = squarerdx -# asm 1: mov squaret3=int64#15 -# asm 2: mov squaret3=%rbp -mov %rdx,%rbp - -# qhasm: squarerax = *(uint64 *)(pp + 16) -# asm 1: movq 16(squarerax=int64#7 -# asm 2: movq 16(squarerax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 16) -# asm 1: mulq 16(squarerax=int64#7 -# asm 2: movq 24(squarerax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 24) -# asm 1: mulq 24(squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r11,%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: squarer4 = squarerax -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rax,%r11 - -# qhasm: squarerax = squarer5 -# asm 1: mov squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r12,%rax - -# qhasm: squarer5 = squarerdx -# asm 1: mov squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rdx,%r12 - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? squarer5 += squarerax -# asm 1: add squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r13,%rax - -# qhasm: squarer6 = 0 -# asm 1: mov $0,>squarer6=int64#11 -# asm 2: mov $0,>squarer6=%r13 -mov $0,%r13 - -# qhasm: squarer6 += squarerdx + carry -# asm 1: adc squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %rcx,%rax - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarer7 += squarerdx + carry -# asm 1: adc squarer8=int64#7 -# asm 2: mov $0,>squarer8=%rax -mov $0,%rax - -# qhasm: squarer8 += squarerdx + carry -# asm 1: adc squarezero=int64#3 -# asm 2: mov $0,>squarezero=%rdx -mov $0,%rdx - -# qhasm: squarer8 += squarezero + carry -# asm 1: adc squarer8=int64#4 -# asm 2: imulq $38,squarer8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? a0 += squarer8 -# asm 1: add squarezero=int64#3 -# asm 2: imulq $38,squarezero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: a0 += squarezero -# asm 1: add a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %r14,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r8,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r9,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %r10,80(%rsp) - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarerax = *(uint64 *)(pp + 40) -# asm 1: movq 40(squarerax=int64#7 -# asm 2: movq 40(squarerax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) -# asm 1: mulq 32(b1=int64#5 -# asm 2: mov b1=%r8 -mov %rax,%r8 - -# qhasm: b2 = squarerdx -# asm 1: mov b2=int64#6 -# asm 2: mov b2=%r9 -mov %rdx,%r9 - -# qhasm: squarerax = *(uint64 *)(pp + 48) -# asm 1: movq 48(squarerax=int64#7 -# asm 2: movq 48(squarerax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 40) -# asm 1: mulq 40(b3=int64#8 -# asm 2: mov b3=%r10 -mov %rax,%r10 - -# qhasm: squarer4 = squarerdx -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rdx,%r11 - -# qhasm: squarerax = *(uint64 *)(pp + 56) -# asm 1: movq 56(squarerax=int64#7 -# asm 2: movq 56(squarerax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 48) -# asm 1: mulq 48(squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rax,%r12 - -# qhasm: squarer6 = squarerdx -# asm 1: mov squarer6=int64#11 -# asm 2: mov squarer6=%r13 -mov %rdx,%r13 - -# qhasm: squarerax = *(uint64 *)(pp + 48) -# asm 1: movq 48(squarerax=int64#7 -# asm 2: movq 48(squarerax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) -# asm 1: mulq 32(squarerax=int64#7 -# asm 2: movq 56(squarerax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 40) -# asm 1: mulq 40(squarerax=int64#7 -# asm 2: movq 56(squarerax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) -# asm 1: mulq 32(squarerax=int64#7 -# asm 2: movq 32(squarerax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 32) -# asm 1: mulq 32(b0=int64#12 -# asm 2: mov b0=%r14 -mov %rax,%r14 - -# qhasm: squaret1 = squarerdx -# asm 1: mov squaret1=int64#13 -# asm 2: mov squaret1=%r15 -mov %rdx,%r15 - -# qhasm: squarerax = *(uint64 *)(pp + 40) -# asm 1: movq 40(squarerax=int64#7 -# asm 2: movq 40(squarerax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 40) -# asm 1: mulq 40(squaret2=int64#14 -# asm 2: mov squaret2=%rbx -mov %rax,%rbx - -# qhasm: squaret3 = squarerdx -# asm 1: mov squaret3=int64#15 -# asm 2: mov squaret3=%rbp -mov %rdx,%rbp - -# qhasm: squarerax = *(uint64 *)(pp + 48) -# asm 1: movq 48(squarerax=int64#7 -# asm 2: movq 48(squarerax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 48) -# asm 1: mulq 48(squarerax=int64#7 -# asm 2: movq 56(squarerax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 56) -# asm 1: mulq 56(squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r11,%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: squarer4 = squarerax -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rax,%r11 - -# qhasm: squarerax = squarer5 -# asm 1: mov squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r12,%rax - -# qhasm: squarer5 = squarerdx -# asm 1: mov squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rdx,%r12 - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? squarer5 += squarerax -# asm 1: add squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r13,%rax - -# qhasm: squarer6 = 0 -# asm 1: mov $0,>squarer6=int64#11 -# asm 2: mov $0,>squarer6=%r13 -mov $0,%r13 - -# qhasm: squarer6 += squarerdx + carry -# asm 1: adc squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %rcx,%rax - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarer7 += squarerdx + carry -# asm 1: adc squarer8=int64#7 -# asm 2: mov $0,>squarer8=%rax -mov $0,%rax - -# qhasm: squarer8 += squarerdx + carry -# asm 1: adc squarezero=int64#3 -# asm 2: mov $0,>squarezero=%rdx -mov $0,%rdx - -# qhasm: squarer8 += squarezero + carry -# asm 1: adc squarer8=int64#4 -# asm 2: imulq $38,squarer8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? b0 += squarer8 -# asm 1: add squarezero=int64#3 -# asm 2: imulq $38,squarezero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: b0 += squarezero -# asm 1: add b0_stack=stack64#12 -# asm 2: movq b0_stack=88(%rsp) -movq %r14,88(%rsp) - -# qhasm: b1_stack = b1 -# asm 1: movq b1_stack=stack64#13 -# asm 2: movq b1_stack=96(%rsp) -movq %r8,96(%rsp) - -# qhasm: b2_stack = b2 -# asm 1: movq b2_stack=stack64#14 -# asm 2: movq b2_stack=104(%rsp) -movq %r9,104(%rsp) - -# qhasm: b3_stack = b3 -# asm 1: movq b3_stack=stack64#15 -# asm 2: movq b3_stack=112(%rsp) -movq %r10,112(%rsp) - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarerax = *(uint64 *)(pp + 72) -# asm 1: movq 72(squarerax=int64#7 -# asm 2: movq 72(squarerax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) -# asm 1: mulq 64(c1=int64#5 -# asm 2: mov c1=%r8 -mov %rax,%r8 - -# qhasm: c2 = squarerdx -# asm 1: mov c2=int64#6 -# asm 2: mov c2=%r9 -mov %rdx,%r9 - -# qhasm: squarerax = *(uint64 *)(pp + 80) -# asm 1: movq 80(squarerax=int64#7 -# asm 2: movq 80(squarerax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 72) -# asm 1: mulq 72(c3=int64#8 -# asm 2: mov c3=%r10 -mov %rax,%r10 - -# qhasm: squarer4 = squarerdx -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rdx,%r11 - -# qhasm: squarerax = *(uint64 *)(pp + 88) -# asm 1: movq 88(squarerax=int64#7 -# asm 2: movq 88(squarerax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 80) -# asm 1: mulq 80(squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rax,%r12 - -# qhasm: squarer6 = squarerdx -# asm 1: mov squarer6=int64#11 -# asm 2: mov squarer6=%r13 -mov %rdx,%r13 - -# qhasm: squarerax = *(uint64 *)(pp + 80) -# asm 1: movq 80(squarerax=int64#7 -# asm 2: movq 80(squarerax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) -# asm 1: mulq 64(squarerax=int64#7 -# asm 2: movq 88(squarerax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 72) -# asm 1: mulq 72(squarerax=int64#7 -# asm 2: movq 88(squarerax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) -# asm 1: mulq 64(squarerax=int64#7 -# asm 2: movq 64(squarerax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 64) -# asm 1: mulq 64(c0=int64#12 -# asm 2: mov c0=%r14 -mov %rax,%r14 - -# qhasm: squaret1 = squarerdx -# asm 1: mov squaret1=int64#13 -# asm 2: mov squaret1=%r15 -mov %rdx,%r15 - -# qhasm: squarerax = *(uint64 *)(pp + 72) -# asm 1: movq 72(squarerax=int64#7 -# asm 2: movq 72(squarerax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 72) -# asm 1: mulq 72(squaret2=int64#14 -# asm 2: mov squaret2=%rbx -mov %rax,%rbx - -# qhasm: squaret3 = squarerdx -# asm 1: mov squaret3=int64#15 -# asm 2: mov squaret3=%rbp -mov %rdx,%rbp - -# qhasm: squarerax = *(uint64 *)(pp + 80) -# asm 1: movq 80(squarerax=int64#7 -# asm 2: movq 80(squarerax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 80) -# asm 1: mulq 80(squarerax=int64#7 -# asm 2: movq 88(squarerax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)(pp + 88) -# asm 1: mulq 88(squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r11,%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: squarer4 = squarerax -# asm 1: mov squarer4=int64#9 -# asm 2: mov squarer4=%r11 -mov %rax,%r11 - -# qhasm: squarerax = squarer5 -# asm 1: mov squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r12,%rax - -# qhasm: squarer5 = squarerdx -# asm 1: mov squarer5=int64#10 -# asm 2: mov squarer5=%r12 -mov %rdx,%r12 - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? squarer5 += squarerax -# asm 1: add squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r13,%rax - -# qhasm: squarer6 = 0 -# asm 1: mov $0,>squarer6=int64#11 -# asm 2: mov $0,>squarer6=%r13 -mov $0,%r13 - -# qhasm: squarer6 += squarerdx + carry -# asm 1: adc squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %rcx,%rax - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#4 -# asm 2: mov $0,>squarer7=%rcx -mov $0,%rcx - -# qhasm: squarer7 += squarerdx + carry -# asm 1: adc squarer8=int64#7 -# asm 2: mov $0,>squarer8=%rax -mov $0,%rax - -# qhasm: squarer8 += squarerdx + carry -# asm 1: adc squarezero=int64#3 -# asm 2: mov $0,>squarezero=%rdx -mov $0,%rdx - -# qhasm: squarer8 += squarezero + carry -# asm 1: adc squarer8=int64#4 -# asm 2: imulq $38,squarer8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? c0 += squarer8 -# asm 1: add squarezero=int64#3 -# asm 2: imulq $38,squarezero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: c0 += squarezero -# asm 1: add addt0=int64#3 -# asm 2: mov $0,>addt0=%rdx -mov $0,%rdx - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#4 -# asm 2: mov $38,>addt1=%rcx -mov $38,%rcx - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae c0_stack=stack64#16 -# asm 2: movq c0_stack=120(%rsp) -movq %r14,120(%rsp) - -# qhasm: c1_stack = c1 -# asm 1: movq c1_stack=stack64#17 -# asm 2: movq c1_stack=128(%rsp) -movq %r8,128(%rsp) - -# qhasm: c2_stack = c2 -# asm 1: movq c2_stack=stack64#18 -# asm 2: movq c2_stack=136(%rsp) -movq %r9,136(%rsp) - -# qhasm: c3_stack = c3 -# asm 1: movq c3_stack=stack64#19 -# asm 2: movq c3_stack=144(%rsp) -movq %r10,144(%rsp) - -# qhasm: d0 = 0 -# asm 1: mov $0,>d0=int64#3 -# asm 2: mov $0,>d0=%rdx -mov $0,%rdx - -# qhasm: d1 = 0 -# asm 1: mov $0,>d1=int64#4 -# asm 2: mov $0,>d1=%rcx -mov $0,%rcx - -# qhasm: d2 = 0 -# asm 1: mov $0,>d2=int64#5 -# asm 2: mov $0,>d2=%r8 -mov $0,%r8 - -# qhasm: d3 = 0 -# asm 1: mov $0,>d3=int64#6 -# asm 2: mov $0,>d3=%r9 -mov $0,%r9 - -# qhasm: carry? d0 -= a0_stack -# asm 1: subq subt0=int64#7 -# asm 2: mov $0,>subt0=%rax -mov $0,%rax - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#8 -# asm 2: mov $38,>subt1=%r10 -mov $38,%r10 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae d0_stack=stack64#8 -# asm 2: movq d0_stack=56(%rsp) -movq %rdx,56(%rsp) - -# qhasm: d1_stack = d1 -# asm 1: movq d1_stack=stack64#9 -# asm 2: movq d1_stack=64(%rsp) -movq %rcx,64(%rsp) - -# qhasm: d2_stack = d2 -# asm 1: movq d2_stack=stack64#10 -# asm 2: movq d2_stack=72(%rsp) -movq %r8,72(%rsp) - -# qhasm: d3_stack = d3 -# asm 1: movq d3_stack=stack64#11 -# asm 2: movq d3_stack=80(%rsp) -movq %r9,80(%rsp) - -# qhasm: e0 = 0 -# asm 1: mov $0,>e0=int64#7 -# asm 2: mov $0,>e0=%rax -mov $0,%rax - -# qhasm: e1 = 0 -# asm 1: mov $0,>e1=int64#8 -# asm 2: mov $0,>e1=%r10 -mov $0,%r10 - -# qhasm: e2 = 0 -# asm 1: mov $0,>e2=int64#9 -# asm 2: mov $0,>e2=%r11 -mov $0,%r11 - -# qhasm: e3 = 0 -# asm 1: mov $0,>e3=int64#10 -# asm 2: mov $0,>e3=%r12 -mov $0,%r12 - -# qhasm: carry? e0 -= b0_stack -# asm 1: subq subt0=int64#11 -# asm 2: mov $0,>subt0=%r13 -mov $0,%r13 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#12 -# asm 2: mov $38,>subt1=%r14 -mov $38,%r14 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae e0_stack=stack64#20 -# asm 2: movq e0_stack=152(%rsp) -movq %rax,152(%rsp) - -# qhasm: e1_stack = e1 -# asm 1: movq e1_stack=stack64#21 -# asm 2: movq e1_stack=160(%rsp) -movq %r10,160(%rsp) - -# qhasm: e2_stack = e2 -# asm 1: movq e2_stack=stack64#22 -# asm 2: movq e2_stack=168(%rsp) -movq %r11,168(%rsp) - -# qhasm: e3_stack = e3 -# asm 1: movq e3_stack=stack64#23 -# asm 2: movq e3_stack=176(%rsp) -movq %r12,176(%rsp) - -# qhasm: rz0 = d0 -# asm 1: mov rz0=int64#7 -# asm 2: mov rz0=%rax -mov %rdx,%rax - -# qhasm: rz1 = d1 -# asm 1: mov rz1=int64#8 -# asm 2: mov rz1=%r10 -mov %rcx,%r10 - -# qhasm: rz2 = d2 -# asm 1: mov rz2=int64#9 -# asm 2: mov rz2=%r11 -mov %r8,%r11 - -# qhasm: rz3 = d3 -# asm 1: mov rz3=int64#10 -# asm 2: mov rz3=%r12 -mov %r9,%r12 - -# qhasm: carry? rz0 += b0_stack -# asm 1: addq addt0=int64#11 -# asm 2: mov $0,>addt0=%r13 -mov $0,%r13 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#12 -# asm 2: mov $38,>addt1=%r14 -mov $38,%r14 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae subt0=int64#11 -# asm 2: mov $0,>subt0=%r13 -mov $0,%r13 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#12 -# asm 2: mov $38,>subt1=%r14 -mov $38,%r14 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae subt0=int64#3 -# asm 2: mov $0,>subt0=%rdx -mov $0,%rdx - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#4 -# asm 2: mov $38,>subt1=%rcx -mov $38,%rcx - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae rx0=int64#3 -# asm 2: movq 0(rx0=%rdx -movq 0(%rsi),%rdx - -# qhasm: rx1 = *(uint64 *)(pp + 8) -# asm 1: movq 8(rx1=int64#4 -# asm 2: movq 8(rx1=%rcx -movq 8(%rsi),%rcx - -# qhasm: rx2 = *(uint64 *)(pp + 16) -# asm 1: movq 16(rx2=int64#5 -# asm 2: movq 16(rx2=%r8 -movq 16(%rsi),%r8 - -# qhasm: rx3 = *(uint64 *)(pp + 24) -# asm 1: movq 24(rx3=int64#6 -# asm 2: movq 24(rx3=%r9 -movq 24(%rsi),%r9 - -# qhasm: carry? rx0 += *(uint64 *)(pp + 32) -# asm 1: addq 32(addt0=int64#2 -# asm 2: mov $0,>addt0=%rsi -mov $0,%rsi - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#7 -# asm 2: mov $38,>addt1=%rax -mov $38,%rax - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae rx0_stack=stack64#12 -# asm 2: movq rx0_stack=88(%rsp) -movq %rdx,88(%rsp) - -# qhasm: rx1_stack = rx1 -# asm 1: movq rx1_stack=stack64#13 -# asm 2: movq rx1_stack=96(%rsp) -movq %rcx,96(%rsp) - -# qhasm: rx2_stack = rx2 -# asm 1: movq rx2_stack=stack64#14 -# asm 2: movq rx2_stack=104(%rsp) -movq %r8,104(%rsp) - -# qhasm: rx3_stack = rx3 -# asm 1: movq rx3_stack=stack64#15 -# asm 2: movq rx3_stack=112(%rsp) -movq %r9,112(%rsp) - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#2 -# asm 2: mov $0,>squarer7=%rsi -mov $0,%rsi - -# qhasm: squarerax = rx1_stack -# asm 1: movq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 96(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack -# asm 1: mulq rx1=int64#4 -# asm 2: mov rx1=%rcx -mov %rax,%rcx - -# qhasm: rx2 = squarerdx -# asm 1: mov rx2=int64#5 -# asm 2: mov rx2=%r8 -mov %rdx,%r8 - -# qhasm: squarerax = rx2_stack -# asm 1: movq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 104(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx1_stack -# asm 1: mulq rx3=int64#6 -# asm 2: mov rx3=%r9 -mov %rax,%r9 - -# qhasm: squarer4 = squarerdx -# asm 1: mov squarer4=int64#8 -# asm 2: mov squarer4=%r10 -mov %rdx,%r10 - -# qhasm: squarerax = rx3_stack -# asm 1: movq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 112(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx2_stack -# asm 1: mulq squarer5=int64#9 -# asm 2: mov squarer5=%r11 -mov %rax,%r11 - -# qhasm: squarer6 = squarerdx -# asm 1: mov squarer6=int64#10 -# asm 2: mov squarer6=%r12 -mov %rdx,%r12 - -# qhasm: squarerax = rx2_stack -# asm 1: movq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 104(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack -# asm 1: mulq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 112(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx1_stack -# asm 1: mulq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 112(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack -# asm 1: mulq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 88(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx0_stack -# asm 1: mulq rx0=int64#11 -# asm 2: mov rx0=%r13 -mov %rax,%r13 - -# qhasm: squaret1 = squarerdx -# asm 1: mov squaret1=int64#12 -# asm 2: mov squaret1=%r14 -mov %rdx,%r14 - -# qhasm: squarerax = rx1_stack -# asm 1: movq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 96(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx1_stack -# asm 1: mulq squaret2=int64#13 -# asm 2: mov squaret2=%r15 -mov %rax,%r15 - -# qhasm: squaret3 = squarerdx -# asm 1: mov squaret3=int64#14 -# asm 2: mov squaret3=%rbx -mov %rdx,%rbx - -# qhasm: squarerax = rx2_stack -# asm 1: movq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 104(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx2_stack -# asm 1: mulq squarerax=int64#7 -# asm 2: movq squarerax=%rax -movq 112(%rsp),%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * rx3_stack -# asm 1: mulq squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r10,%rax - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: squarer4 = squarerax -# asm 1: mov squarer4=int64#8 -# asm 2: mov squarer4=%r10 -mov %rax,%r10 - -# qhasm: squarerax = squarer5 -# asm 1: mov squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r11,%rax - -# qhasm: squarer5 = squarerdx -# asm 1: mov squarer5=int64#9 -# asm 2: mov squarer5=%r11 -mov %rdx,%r11 - -# qhasm: (uint128) squarerdx squarerax = squarerax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? squarer5 += squarerax -# asm 1: add squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %r12,%rax - -# qhasm: squarer6 = 0 -# asm 1: mov $0,>squarer6=int64#10 -# asm 2: mov $0,>squarer6=%r12 -mov $0,%r12 - -# qhasm: squarer6 += squarerdx + carry -# asm 1: adc squarerax=int64#7 -# asm 2: mov squarerax=%rax -mov %rsi,%rax - -# qhasm: squarer7 = 0 -# asm 1: mov $0,>squarer7=int64#2 -# asm 2: mov $0,>squarer7=%rsi -mov $0,%rsi - -# qhasm: squarer7 += squarerdx + carry -# asm 1: adc squarer8=int64#7 -# asm 2: mov $0,>squarer8=%rax -mov $0,%rax - -# qhasm: squarer8 += squarerdx + carry -# asm 1: adc squarezero=int64#2 -# asm 2: mov $0,>squarezero=%rsi -mov $0,%rsi - -# qhasm: squarer8 += squarezero + carry -# asm 1: adc squarer8=int64#3 -# asm 2: imulq $38,squarer8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rx0 += squarer8 -# asm 1: add squarezero=int64#2 -# asm 2: imulq $38,squarezero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rx0 += squarezero -# asm 1: add addt0=int64#2 -# asm 2: mov $0,>addt0=%rsi -mov $0,%rsi - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#3 -# asm 2: mov $38,>addt1=%rdx -mov $38,%rdx - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae addt0=int64#2 -# asm 2: mov $0,>addt0=%rsi -mov $0,%rsi - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#3 -# asm 2: mov $38,>addt1=%rdx -mov $38,%rdx - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_double.c b/ext/ed25519-amd64-asm/ge25519_double.c deleted file mode 100644 index d55e2b4f..00000000 --- a/ext/ed25519-amd64-asm/ge25519_double.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "ge25519.h" - -void ge25519_double(ge25519_p3 *r, const ge25519_p3 *p) -{ - ge25519_p1p1 grp1p1; - ge25519_dbl_p1p1(&grp1p1, (ge25519_p2 *)p); - ge25519_p1p1_to_p3(r, &grp1p1); -} diff --git a/ext/ed25519-amd64-asm/ge25519_double_scalarmult.c b/ext/ed25519-amd64-asm/ge25519_double_scalarmult.c deleted file mode 100644 index 30c922af..00000000 --- a/ext/ed25519-amd64-asm/ge25519_double_scalarmult.c +++ /dev/null @@ -1,102 +0,0 @@ -#include "fe25519.h" -#include "sc25519.h" -#include "ge25519.h" - -#define S1_SWINDOWSIZE 5 -#define PRE1_SIZE (1<<(S1_SWINDOWSIZE-2)) -#define S2_SWINDOWSIZE 7 -#define PRE2_SIZE (1<<(S2_SWINDOWSIZE-2)) - -ge25519_niels pre2[PRE2_SIZE] = { -#include "ge25519_base_slide_multiples.data" -}; - -static const fe25519 ec2d = {{0xEBD69B9426B2F146, 0x00E0149A8283B156, 0x198E80F2EEF3D130, 0xA406D9DC56DFFCE7}}; - -static void setneutral(ge25519 *r) -{ - fe25519_setint(&r->x,0); - fe25519_setint(&r->y,1); - fe25519_setint(&r->z,1); - fe25519_setint(&r->t,0); -} - -/* computes [s1]p1 + [s2]p2 */ -void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const sc25519 *s2) -{ - signed char slide1[256], slide2[256]; - ge25519_pniels pre1[PRE1_SIZE], neg; - ge25519_p3 d1; - ge25519_p1p1 t; - ge25519_niels nneg; - fe25519 d; - int i; - - sc25519_slide(slide1, s1, S1_SWINDOWSIZE); - sc25519_slide(slide2, s2, S2_SWINDOWSIZE); - - /* precomputation */ - pre1[0] = *(ge25519_pniels *)p1; - ge25519_dbl_p1p1(&t,(ge25519_p2 *)pre1); ge25519_p1p1_to_p3(&d1, &t); - /* Convert pre[0] to projective Niels representation */ - d = pre1[0].ysubx; - fe25519_sub(&pre1[0].ysubx, &pre1[0].xaddy, &pre1[0].ysubx); - fe25519_add(&pre1[0].xaddy, &pre1[0].xaddy, &d); - fe25519_mul(&pre1[0].t2d, &pre1[0].t2d, &ec2d); - - for(i=0;i= 0;--i) { - if (slide1[i] || slide2[i]) goto firstbit; - } - - for(;i>=0;i--) - { - firstbit: - - ge25519_dbl_p1p1(&t, (ge25519_p2 *)r); - - if(slide1[i]>0) - { - ge25519_p1p1_to_p3(r, &t); - ge25519_pnielsadd_p1p1(&t, r, &pre1[slide1[i]/2]); - } - else if(slide1[i]<0) - { - ge25519_p1p1_to_p3(r, &t); - neg = pre1[-slide1[i]/2]; - d = neg.ysubx; - neg.ysubx = neg.xaddy; - neg.xaddy = d; - fe25519_neg(&neg.t2d, &neg.t2d); - ge25519_pnielsadd_p1p1(&t, r, &neg); - } - - if(slide2[i]>0) - { - ge25519_p1p1_to_p3(r, &t); - ge25519_nielsadd_p1p1(&t, r, &pre2[slide2[i]/2]); - } - else if(slide2[i]<0) - { - ge25519_p1p1_to_p3(r, &t); - nneg = pre2[-slide2[i]/2]; - d = nneg.ysubx; - nneg.ysubx = nneg.xaddy; - nneg.xaddy = d; - fe25519_neg(&nneg.t2d, &nneg.t2d); - ge25519_nielsadd_p1p1(&t, r, &nneg); - } - - ge25519_p1p1_to_p2((ge25519_p2 *)r, &t); - } -} diff --git a/ext/ed25519-amd64-asm/ge25519_isneutral.c b/ext/ed25519-amd64-asm/ge25519_isneutral.c deleted file mode 100644 index cf566dba..00000000 --- a/ext/ed25519-amd64-asm/ge25519_isneutral.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "fe25519.h" -#include "ge25519.h" - -int ge25519_isneutral_vartime(const ge25519_p3 *p) -{ - if(!fe25519_iszero_vartime(&p->x)) return 0; - if(!fe25519_iseq_vartime(&p->y, &p->z)) return 0; - return 1; -} diff --git a/ext/ed25519-amd64-asm/ge25519_multi_scalarmult.c b/ext/ed25519-amd64-asm/ge25519_multi_scalarmult.c deleted file mode 100644 index afc6aeae..00000000 --- a/ext/ed25519-amd64-asm/ge25519_multi_scalarmult.c +++ /dev/null @@ -1,102 +0,0 @@ -#include "fe25519.h" -#include "sc25519.h" -#include "ge25519.h" -#include "index_heap.h" - -static void setneutral(ge25519 *r) -{ - fe25519_setint(&r->x,0); - fe25519_setint(&r->y,1); - fe25519_setint(&r->z,1); - fe25519_setint(&r->t,0); -} - -static void ge25519_scalarmult_vartime_2limbs(ge25519 *r, ge25519 *p, sc25519 *s) -{ - if (s->v[1] == 0 && s->v[0] == 1) /* This will happen most of the time after Bos-Coster */ - *r = *p; - else if (s->v[1] == 0 && s->v[0] == 0) /* This won't ever happen, except for all scalars == 0 in Bos-Coster */ - setneutral(r); - else - { - ge25519 d; - unsigned long long mask = (1ULL << 63); - int i = 1; - while(!(mask & s->v[1]) && mask != 0) - mask >>= 1; - if(mask == 0) - { - mask = (1ULL << 63); - i = 0; - while(!(mask & s->v[0]) && mask != 0) - mask >>= 1; - } - d = *p; - mask >>= 1; - for(;mask != 0;mask >>= 1) - { - ge25519_double(&d,&d); - if(s->v[i] & mask) - ge25519_add(&d,&d,p); - } - if(i==1) - { - mask = (1ULL << 63); - for(;mask != 0;mask >>= 1) - { - ge25519_double(&d,&d); - if(s->v[0] & mask) - ge25519_add(&d,&d,p); - } - } - *r = d; - } -} - -/* caller's responsibility to ensure npoints >= 5 */ -void ge25519_multi_scalarmult_vartime(ge25519_p3 *r, ge25519_p3 *p, sc25519 *s, const unsigned long long npoints) -{ - unsigned long long pos[npoints]; - unsigned long long hlen=((npoints+1)/2)|1; - unsigned long long max1, max2,i; - - heap_init(pos, hlen, s); - - for(i=0;;i++) - { - heap_get2max(pos, &max1, &max2, s); - if((s[max1].v[3] == 0) || (sc25519_iszero_vartime(&s[max2]))) break; - sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); - ge25519_add(&p[max2],&p[max2],&p[max1]); - heap_rootreplaced(pos, hlen, s); - } - for(;;i++) - { - heap_get2max(pos, &max1, &max2, s); - if((s[max1].v[2] == 0) || (sc25519_iszero_vartime(&s[max2]))) break; - sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); - ge25519_add(&p[max2],&p[max2],&p[max1]); - heap_rootreplaced_3limbs(pos, hlen, s); - } - /* We know that (npoints-1)/2 scalars are only 128-bit scalars */ - heap_extend(pos, hlen, npoints, s); - hlen = npoints; - for(;;i++) - { - heap_get2max(pos, &max1, &max2, s); - if((s[max1].v[1] == 0) || (sc25519_iszero_vartime(&s[max2]))) break; - sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); - ge25519_add(&p[max2],&p[max2],&p[max1]); - heap_rootreplaced_2limbs(pos, hlen, s); - } - for(;;i++) - { - heap_get2max(pos, &max1, &max2, s); - if(sc25519_iszero_vartime(&s[max2])) break; - sc25519_sub_nored(&s[max1],&s[max1],&s[max2]); - ge25519_add(&p[max2],&p[max2],&p[max1]); - heap_rootreplaced_1limb(pos, hlen, s); - } - - ge25519_scalarmult_vartime_2limbs(r, &p[max1], &s[max1]); -} diff --git a/ext/ed25519-amd64-asm/ge25519_nielsadd2.s b/ext/ed25519-amd64-asm/ge25519_nielsadd2.s deleted file mode 100644 index 19d71f11..00000000 --- a/ext/ed25519-amd64-asm/ge25519_nielsadd2.s +++ /dev/null @@ -1,5791 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 qp - -# qhasm: input rp - -# qhasm: input qp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 a0 - -# qhasm: int64 a1 - -# qhasm: int64 a2 - -# qhasm: int64 a3 - -# qhasm: stack64 a0_stack - -# qhasm: stack64 a1_stack - -# qhasm: stack64 a2_stack - -# qhasm: stack64 a3_stack - -# qhasm: int64 b0 - -# qhasm: int64 b1 - -# qhasm: int64 b2 - -# qhasm: int64 b3 - -# qhasm: stack64 b0_stack - -# qhasm: stack64 b1_stack - -# qhasm: stack64 b2_stack - -# qhasm: stack64 b3_stack - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: stack64 c0_stack - -# qhasm: stack64 c1_stack - -# qhasm: stack64 c2_stack - -# qhasm: stack64 c3_stack - -# qhasm: int64 d0 - -# qhasm: int64 d1 - -# qhasm: int64 d2 - -# qhasm: int64 d3 - -# qhasm: stack64 d0_stack - -# qhasm: stack64 d1_stack - -# qhasm: stack64 d2_stack - -# qhasm: stack64 d3_stack - -# qhasm: int64 e0 - -# qhasm: int64 e1 - -# qhasm: int64 e2 - -# qhasm: int64 e3 - -# qhasm: stack64 e0_stack - -# qhasm: stack64 e1_stack - -# qhasm: stack64 e2_stack - -# qhasm: stack64 e3_stack - -# qhasm: int64 f0 - -# qhasm: int64 f1 - -# qhasm: int64 f2 - -# qhasm: int64 f3 - -# qhasm: stack64 f0_stack - -# qhasm: stack64 f1_stack - -# qhasm: stack64 f2_stack - -# qhasm: stack64 f3_stack - -# qhasm: int64 g0 - -# qhasm: int64 g1 - -# qhasm: int64 g2 - -# qhasm: int64 g3 - -# qhasm: stack64 g0_stack - -# qhasm: stack64 g1_stack - -# qhasm: stack64 g2_stack - -# qhasm: stack64 g3_stack - -# qhasm: int64 h0 - -# qhasm: int64 h1 - -# qhasm: int64 h2 - -# qhasm: int64 h3 - -# qhasm: stack64 h0_stack - -# qhasm: stack64 h1_stack - -# qhasm: stack64 h2_stack - -# qhasm: stack64 h3_stack - -# qhasm: int64 qt0 - -# qhasm: int64 qt1 - -# qhasm: int64 qt2 - -# qhasm: int64 qt3 - -# qhasm: stack64 qt0_stack - -# qhasm: stack64 qt1_stack - -# qhasm: stack64 qt2_stack - -# qhasm: stack64 qt3_stack - -# qhasm: int64 t10 - -# qhasm: int64 t11 - -# qhasm: int64 t12 - -# qhasm: int64 t13 - -# qhasm: stack64 t10_stack - -# qhasm: stack64 t11_stack - -# qhasm: stack64 t12_stack - -# qhasm: stack64 t13_stack - -# qhasm: int64 t20 - -# qhasm: int64 t21 - -# qhasm: int64 t22 - -# qhasm: int64 t23 - -# qhasm: stack64 t20_stack - -# qhasm: stack64 t21_stack - -# qhasm: stack64 t22_stack - -# qhasm: stack64 t23_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 rt0 - -# qhasm: int64 rt1 - -# qhasm: int64 rt2 - -# qhasm: int64 rt3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: int64 addt0 - -# qhasm: int64 addt1 - -# qhasm: int64 subt0 - -# qhasm: int64 subt1 - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 -.globl crypto_sign_ed25519_amd64_64_ge25519_nielsadd2 -_crypto_sign_ed25519_amd64_64_ge25519_nielsadd2: -crypto_sign_ed25519_amd64_64_ge25519_nielsadd2: -mov %rsp,%r11 -and $31,%r11 -add $192,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: a0 = *(uint64 *)(rp + 32) -# asm 1: movq 32(a0=int64#3 -# asm 2: movq 32(a0=%rdx -movq 32(%rdi),%rdx - -# qhasm: a1 = *(uint64 *)(rp + 40) -# asm 1: movq 40(a1=int64#4 -# asm 2: movq 40(a1=%rcx -movq 40(%rdi),%rcx - -# qhasm: a2 = *(uint64 *)(rp + 48) -# asm 1: movq 48(a2=int64#5 -# asm 2: movq 48(a2=%r8 -movq 48(%rdi),%r8 - -# qhasm: a3 = *(uint64 *)(rp + 56) -# asm 1: movq 56(a3=int64#6 -# asm 2: movq 56(a3=%r9 -movq 56(%rdi),%r9 - -# qhasm: b0 = a0 -# asm 1: mov b0=int64#7 -# asm 2: mov b0=%rax -mov %rdx,%rax - -# qhasm: b1 = a1 -# asm 1: mov b1=int64#8 -# asm 2: mov b1=%r10 -mov %rcx,%r10 - -# qhasm: b2 = a2 -# asm 1: mov b2=int64#9 -# asm 2: mov b2=%r11 -mov %r8,%r11 - -# qhasm: b3 = a3 -# asm 1: mov b3=int64#10 -# asm 2: mov b3=%r12 -mov %r9,%r12 - -# qhasm: carry? a0 -= *(uint64 *) (rp + 0) -# asm 1: subq 0(subt0=int64#11 -# asm 2: mov $0,>subt0=%r13 -mov $0,%r13 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#12 -# asm 2: mov $38,>subt1=%r14 -mov $38,%r14 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#11 -# asm 2: mov $0,>addt0=%r13 -mov $0,%r13 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#12 -# asm 2: mov $38,>addt1=%r14 -mov $38,%r14 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %rdx,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %rcx,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r8,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %r9,80(%rsp) - -# qhasm: b0_stack = b0 -# asm 1: movq b0_stack=stack64#12 -# asm 2: movq b0_stack=88(%rsp) -movq %rax,88(%rsp) - -# qhasm: b1_stack = b1 -# asm 1: movq b1_stack=stack64#13 -# asm 2: movq b1_stack=96(%rsp) -movq %r10,96(%rsp) - -# qhasm: b2_stack = b2 -# asm 1: movq b2_stack=stack64#14 -# asm 2: movq b2_stack=104(%rsp) -movq %r11,104(%rsp) - -# qhasm: b3_stack = b3 -# asm 1: movq b3_stack=stack64#15 -# asm 2: movq b3_stack=112(%rsp) -movq %r12,112(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = a0_stack -# asm 1: movq mulx0=int64#9 -# asm 2: movq mulx0=%r11 -movq 56(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a0=int64#10 -# asm 2: mov a0=%r12 -mov %rax,%r12 - -# qhasm: a1 = mulrdx -# asm 1: mov a1=int64#11 -# asm 2: mov a1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(qp + 8) -# asm 1: movq 8(mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a2=int64#12 -# asm 2: mov $0,>a2=%r14 -mov $0,%r14 - -# qhasm: a2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a3=int64#13 -# asm 2: mov $0,>a3=%r15 -mov $0,%r15 - -# qhasm: a3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq mulx1=%r11 -movq 64(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq mulx2=%r11 -movq 72(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq mulx3=%r11 -movq 80(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? a0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: a0 += mulzero -# asm 1: add a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %r12,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r13,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r14,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %r15,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = b0_stack -# asm 1: movq mulx0=int64#9 -# asm 2: movq mulx0=%r11 -movq 88(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul e0=int64#10 -# asm 2: mov e0=%r12 -mov %rax,%r12 - -# qhasm: e1 = mulrdx -# asm 1: mov e1=int64#11 -# asm 2: mov e1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(qp + 40) -# asm 1: movq 40(mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul e2=int64#12 -# asm 2: mov $0,>e2=%r14 -mov $0,%r14 - -# qhasm: e2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul e3=int64#13 -# asm 2: mov $0,>e3=%r15 -mov $0,%r15 - -# qhasm: e3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq mulx1=%r11 -movq 96(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq mulx2=%r11 -movq 104(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq mulx3=%r11 -movq 112(%rsp),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? e0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: e0 += mulzero -# asm 1: add h0=int64#3 -# asm 2: mov h0=%rdx -mov %r12,%rdx - -# qhasm: h1 = e1 -# asm 1: mov h1=int64#4 -# asm 2: mov h1=%rcx -mov %r13,%rcx - -# qhasm: h2 = e2 -# asm 1: mov h2=int64#5 -# asm 2: mov h2=%r8 -mov %r14,%r8 - -# qhasm: h3 = e3 -# asm 1: mov h3=int64#6 -# asm 2: mov h3=%r9 -mov %r15,%r9 - -# qhasm: carry? e0 -= a0_stack -# asm 1: subq subt0=int64#7 -# asm 2: mov $0,>subt0=%rax -mov $0,%rax - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#8 -# asm 2: mov $38,>subt1=%r10 -mov $38,%r10 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#7 -# asm 2: mov $0,>addt0=%rax -mov $0,%rax - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#8 -# asm 2: mov $38,>addt1=%r10 -mov $38,%r10 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae h0_stack=stack64#8 -# asm 2: movq h0_stack=56(%rsp) -movq %rdx,56(%rsp) - -# qhasm: h1_stack = h1 -# asm 1: movq h1_stack=stack64#9 -# asm 2: movq h1_stack=64(%rsp) -movq %rcx,64(%rsp) - -# qhasm: h2_stack = h2 -# asm 1: movq h2_stack=stack64#10 -# asm 2: movq h2_stack=72(%rsp) -movq %r8,72(%rsp) - -# qhasm: h3_stack = h3 -# asm 1: movq h3_stack=stack64#11 -# asm 2: movq h3_stack=80(%rsp) -movq %r9,80(%rsp) - -# qhasm: e0_stack = e0 -# asm 1: movq e0_stack=stack64#12 -# asm 2: movq e0_stack=88(%rsp) -movq %r12,88(%rsp) - -# qhasm: e1_stack = e1 -# asm 1: movq e1_stack=stack64#13 -# asm 2: movq e1_stack=96(%rsp) -movq %r13,96(%rsp) - -# qhasm: e2_stack = e2 -# asm 1: movq e2_stack=stack64#14 -# asm 2: movq e2_stack=104(%rsp) -movq %r14,104(%rsp) - -# qhasm: e3_stack = e3 -# asm 1: movq e3_stack=stack64#15 -# asm 2: movq e3_stack=112(%rsp) -movq %r15,112(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(rp + 96) -# asm 1: movq 96(mulx0=int64#9 -# asm 2: movq 96(mulx0=%r11 -movq 96(%rdi),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c0=int64#10 -# asm 2: mov c0=%r12 -mov %rax,%r12 - -# qhasm: c1 = mulrdx -# asm 1: mov c1=int64#11 -# asm 2: mov c1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(qp + 72) -# asm 1: movq 72(mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c2=int64#12 -# asm 2: mov $0,>c2=%r14 -mov $0,%r14 - -# qhasm: c2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c3=int64#13 -# asm 2: mov $0,>c3=%r15 -mov $0,%r15 - -# qhasm: c3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 104(mulx1=%r11 -movq 104(%rdi),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 112(mulx2=%r11 -movq 112(%rdi),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 120(mulx3=%r11 -movq 120(%rdi),%r11 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? c0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: c0 += mulzero -# asm 1: add f0=int64#2 -# asm 2: movq 64(f0=%rsi -movq 64(%rdi),%rsi - -# qhasm: f1 = *(uint64 *)(rp + 72) -# asm 1: movq 72(f1=int64#3 -# asm 2: movq 72(f1=%rdx -movq 72(%rdi),%rdx - -# qhasm: f2 = *(uint64 *)(rp + 80) -# asm 1: movq 80(f2=int64#4 -# asm 2: movq 80(f2=%rcx -movq 80(%rdi),%rcx - -# qhasm: f3 = *(uint64 *)(rp + 88) -# asm 1: movq 88(f3=int64#5 -# asm 2: movq 88(f3=%r8 -movq 88(%rdi),%r8 - -# qhasm: carry? f0 += f0 -# asm 1: add addt0=int64#6 -# asm 2: mov $0,>addt0=%r9 -mov $0,%r9 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#7 -# asm 2: mov $38,>addt1=%rax -mov $38,%rax - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae g0=int64#6 -# asm 2: mov g0=%r9 -mov %rsi,%r9 - -# qhasm: g1 = f1 -# asm 1: mov g1=int64#7 -# asm 2: mov g1=%rax -mov %rdx,%rax - -# qhasm: g2 = f2 -# asm 1: mov g2=int64#8 -# asm 2: mov g2=%r10 -mov %rcx,%r10 - -# qhasm: g3 = f3 -# asm 1: mov g3=int64#9 -# asm 2: mov g3=%r11 -mov %r8,%r11 - -# qhasm: carry? f0 -= c0 -# asm 1: sub subt0=int64#14 -# asm 2: mov $0,>subt0=%rbx -mov $0,%rbx - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#15 -# asm 2: mov $38,>subt1=%rbp -mov $38,%rbp - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#10 -# asm 2: mov $0,>addt0=%r12 -mov $0,%r12 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#11 -# asm 2: mov $38,>addt1=%r13 -mov $38,%r13 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae g0_stack=stack64#16 -# asm 2: movq g0_stack=120(%rsp) -movq %r9,120(%rsp) - -# qhasm: g1_stack = g1 -# asm 1: movq g1_stack=stack64#17 -# asm 2: movq g1_stack=128(%rsp) -movq %rax,128(%rsp) - -# qhasm: g2_stack = g2 -# asm 1: movq g2_stack=stack64#18 -# asm 2: movq g2_stack=136(%rsp) -movq %r10,136(%rsp) - -# qhasm: g3_stack = g3 -# asm 1: movq g3_stack=stack64#19 -# asm 2: movq g3_stack=144(%rsp) -movq %r11,144(%rsp) - -# qhasm: f0_stack = f0 -# asm 1: movq f0_stack=stack64#20 -# asm 2: movq f0_stack=152(%rsp) -movq %rsi,152(%rsp) - -# qhasm: f1_stack = f1 -# asm 1: movq f1_stack=stack64#21 -# asm 2: movq f1_stack=160(%rsp) -movq %rdx,160(%rsp) - -# qhasm: f2_stack = f2 -# asm 1: movq f2_stack=stack64#22 -# asm 2: movq f2_stack=168(%rsp) -movq %rcx,168(%rsp) - -# qhasm: f3_stack = f3 -# asm 1: movq f3_stack=stack64#23 -# asm 2: movq f3_stack=176(%rsp) -movq %r8,176(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#2 -# asm 2: mov $0,>mulr4=%rsi -mov $0,%rsi - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#4 -# asm 2: mov $0,>mulr5=%rcx -mov $0,%rcx - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulx0 = e0_stack -# asm 1: movq mulx0=int64#8 -# asm 2: movq mulx0=%r10 -movq 88(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx0=int64#9 -# asm 2: mov rx0=%r11 -mov %rax,%r11 - -# qhasm: rx1 = mulrdx -# asm 1: mov rx1=int64#10 -# asm 2: mov rx1=%r12 -mov %rdx,%r12 - -# qhasm: mulrax = f1_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx2=int64#11 -# asm 2: mov $0,>rx2=%r13 -mov $0,%r13 - -# qhasm: rx2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx3=int64#12 -# asm 2: mov $0,>rx3=%r14 -mov $0,%r14 - -# qhasm: rx3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#8 -# asm 2: movq mulx1=%r10 -movq 96(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#8 -# asm 2: movq mulx2=%r10 -movq 104(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#8 -# asm 2: movq mulx3=%r10 -movq 112(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rsi,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rx0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rx0 += mulzero -# asm 1: add mulr4=int64#2 -# asm 2: mov $0,>mulr4=%rsi -mov $0,%rsi - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#4 -# asm 2: mov $0,>mulr5=%rcx -mov $0,%rcx - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulx0 = h0_stack -# asm 1: movq mulx0=int64#8 -# asm 2: movq mulx0=%r10 -movq 56(%rsp),%r10 - -# qhasm: mulrax = g0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry0=int64#9 -# asm 2: mov ry0=%r11 -mov %rax,%r11 - -# qhasm: ry1 = mulrdx -# asm 1: mov ry1=int64#10 -# asm 2: mov ry1=%r12 -mov %rdx,%r12 - -# qhasm: mulrax = g1_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry2=int64#11 -# asm 2: mov $0,>ry2=%r13 -mov $0,%r13 - -# qhasm: ry2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry3=int64#12 -# asm 2: mov $0,>ry3=%r14 -mov $0,%r14 - -# qhasm: ry3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#8 -# asm 2: movq mulx1=%r10 -movq 64(%rsp),%r10 - -# qhasm: mulrax = g0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#8 -# asm 2: movq mulx2=%r10 -movq 72(%rsp),%r10 - -# qhasm: mulrax = g0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#8 -# asm 2: movq mulx3=%r10 -movq 80(%rsp),%r10 - -# qhasm: mulrax = g0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 120(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 128(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 136(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 144(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rsi,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? ry0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: ry0 += mulzero -# asm 1: add mulr4=int64#2 -# asm 2: mov $0,>mulr4=%rsi -mov $0,%rsi - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#4 -# asm 2: mov $0,>mulr5=%rcx -mov $0,%rcx - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulx0 = g0_stack -# asm 1: movq mulx0=int64#8 -# asm 2: movq mulx0=%r10 -movq 120(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz0=int64#9 -# asm 2: mov rz0=%r11 -mov %rax,%r11 - -# qhasm: rz1 = mulrdx -# asm 1: mov rz1=int64#10 -# asm 2: mov rz1=%r12 -mov %rdx,%r12 - -# qhasm: mulrax = f1_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz2=int64#11 -# asm 2: mov $0,>rz2=%r13 -mov $0,%r13 - -# qhasm: rz2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz3=int64#12 -# asm 2: mov $0,>rz3=%r14 -mov $0,%r14 - -# qhasm: rz3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#8 -# asm 2: movq mulx1=%r10 -movq 128(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#8 -# asm 2: movq mulx2=%r10 -movq 136(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#8 -# asm 2: movq mulx3=%r10 -movq 144(%rsp),%r10 - -# qhasm: mulrax = f0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 152(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 160(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 168(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 176(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rsi,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rz0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rz0 += mulzero -# asm 1: add mulr4=int64#2 -# asm 2: mov $0,>mulr4=%rsi -mov $0,%rsi - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#4 -# asm 2: mov $0,>mulr5=%rcx -mov $0,%rcx - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulx0 = e0_stack -# asm 1: movq mulx0=int64#8 -# asm 2: movq mulx0=%r10 -movq 88(%rsp),%r10 - -# qhasm: mulrax = h0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt0=int64#9 -# asm 2: mov rt0=%r11 -mov %rax,%r11 - -# qhasm: rt1 = mulrdx -# asm 1: mov rt1=int64#10 -# asm 2: mov rt1=%r12 -mov %rdx,%r12 - -# qhasm: mulrax = h1_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt2=int64#11 -# asm 2: mov $0,>rt2=%r13 -mov $0,%r13 - -# qhasm: rt2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 72(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt3=int64#12 -# asm 2: mov $0,>rt3=%r14 -mov $0,%r14 - -# qhasm: rt3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 80(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#8 -# asm 2: movq mulx1=%r10 -movq 96(%rsp),%r10 - -# qhasm: mulrax = h0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 72(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 80(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#8 -# asm 2: movq mulx2=%r10 -movq 104(%rsp),%r10 - -# qhasm: mulrax = h0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 72(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 80(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#8 -# asm 2: movq mulx3=%r10 -movq 112(%rsp),%r10 - -# qhasm: mulrax = h0_stack -# asm 1: movq mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 72(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#13 -# asm 2: mov $0,>mulc=%r15 -mov $0,%r15 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq mulrax=%rax -movq 80(%rsp),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rsi,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rt0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rt0 += mulzero -# asm 1: add caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.s b/ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.s deleted file mode 100644 index b5629462..00000000 --- a/ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.s +++ /dev/null @@ -1,3072 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 pp - -# qhasm: int64 qp - -# qhasm: input rp - -# qhasm: input pp - -# qhasm: input qp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 a0 - -# qhasm: int64 a1 - -# qhasm: int64 a2 - -# qhasm: int64 a3 - -# qhasm: stack64 a0_stack - -# qhasm: stack64 a1_stack - -# qhasm: stack64 a2_stack - -# qhasm: stack64 a3_stack - -# qhasm: int64 b0 - -# qhasm: int64 b1 - -# qhasm: int64 b2 - -# qhasm: int64 b3 - -# qhasm: stack64 b0_stack - -# qhasm: stack64 b1_stack - -# qhasm: stack64 b2_stack - -# qhasm: stack64 b3_stack - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: stack64 c0_stack - -# qhasm: stack64 c1_stack - -# qhasm: stack64 c2_stack - -# qhasm: stack64 c3_stack - -# qhasm: int64 d0 - -# qhasm: int64 d1 - -# qhasm: int64 d2 - -# qhasm: int64 d3 - -# qhasm: stack64 d0_stack - -# qhasm: stack64 d1_stack - -# qhasm: stack64 d2_stack - -# qhasm: stack64 d3_stack - -# qhasm: int64 e0 - -# qhasm: int64 e1 - -# qhasm: int64 e2 - -# qhasm: int64 e3 - -# qhasm: stack64 e0_stack - -# qhasm: stack64 e1_stack - -# qhasm: stack64 e2_stack - -# qhasm: stack64 e3_stack - -# qhasm: int64 f0 - -# qhasm: int64 f1 - -# qhasm: int64 f2 - -# qhasm: int64 f3 - -# qhasm: stack64 f0_stack - -# qhasm: stack64 f1_stack - -# qhasm: stack64 f2_stack - -# qhasm: stack64 f3_stack - -# qhasm: int64 g0 - -# qhasm: int64 g1 - -# qhasm: int64 g2 - -# qhasm: int64 g3 - -# qhasm: stack64 g0_stack - -# qhasm: stack64 g1_stack - -# qhasm: stack64 g2_stack - -# qhasm: stack64 g3_stack - -# qhasm: int64 h0 - -# qhasm: int64 h1 - -# qhasm: int64 h2 - -# qhasm: int64 h3 - -# qhasm: stack64 h0_stack - -# qhasm: stack64 h1_stack - -# qhasm: stack64 h2_stack - -# qhasm: stack64 h3_stack - -# qhasm: int64 qt0 - -# qhasm: int64 qt1 - -# qhasm: int64 qt2 - -# qhasm: int64 qt3 - -# qhasm: stack64 qt0_stack - -# qhasm: stack64 qt1_stack - -# qhasm: stack64 qt2_stack - -# qhasm: stack64 qt3_stack - -# qhasm: int64 t10 - -# qhasm: int64 t11 - -# qhasm: int64 t12 - -# qhasm: int64 t13 - -# qhasm: stack64 t10_stack - -# qhasm: stack64 t11_stack - -# qhasm: stack64 t12_stack - -# qhasm: stack64 t13_stack - -# qhasm: int64 t20 - -# qhasm: int64 t21 - -# qhasm: int64 t22 - -# qhasm: int64 t23 - -# qhasm: stack64 t20_stack - -# qhasm: stack64 t21_stack - -# qhasm: stack64 t22_stack - -# qhasm: stack64 t23_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 rt0 - -# qhasm: int64 rt1 - -# qhasm: int64 rt2 - -# qhasm: int64 rt3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: int64 addt0 - -# qhasm: int64 addt1 - -# qhasm: int64 subt0 - -# qhasm: int64 subt1 - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 -.globl crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1 -_crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1: -crypto_sign_ed25519_amd64_64_ge25519_nielsadd_p1p1: -mov %rsp,%r11 -and $31,%r11 -add $128,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: qp = qp -# asm 1: mov qp=int64#4 -# asm 2: mov qp=%rcx -mov %rdx,%rcx - -# qhasm: a0 = *(uint64 *)(pp + 32) -# asm 1: movq 32(a0=int64#3 -# asm 2: movq 32(a0=%rdx -movq 32(%rsi),%rdx - -# qhasm: a1 = *(uint64 *)(pp + 40) -# asm 1: movq 40(a1=int64#5 -# asm 2: movq 40(a1=%r8 -movq 40(%rsi),%r8 - -# qhasm: a2 = *(uint64 *)(pp + 48) -# asm 1: movq 48(a2=int64#6 -# asm 2: movq 48(a2=%r9 -movq 48(%rsi),%r9 - -# qhasm: a3 = *(uint64 *)(pp + 56) -# asm 1: movq 56(a3=int64#7 -# asm 2: movq 56(a3=%rax -movq 56(%rsi),%rax - -# qhasm: b0 = a0 -# asm 1: mov b0=int64#8 -# asm 2: mov b0=%r10 -mov %rdx,%r10 - -# qhasm: b1 = a1 -# asm 1: mov b1=int64#9 -# asm 2: mov b1=%r11 -mov %r8,%r11 - -# qhasm: b2 = a2 -# asm 1: mov b2=int64#10 -# asm 2: mov b2=%r12 -mov %r9,%r12 - -# qhasm: b3 = a3 -# asm 1: mov b3=int64#11 -# asm 2: mov b3=%r13 -mov %rax,%r13 - -# qhasm: carry? a0 -= *(uint64 *) (pp + 0) -# asm 1: subq 0(subt0=int64#12 -# asm 2: mov $0,>subt0=%r14 -mov $0,%r14 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#13 -# asm 2: mov $38,>subt1=%r15 -mov $38,%r15 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#12 -# asm 2: mov $0,>addt0=%r14 -mov $0,%r14 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#13 -# asm 2: mov $38,>addt1=%r15 -mov $38,%r15 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %rdx,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r8,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r9,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %rax,80(%rsp) - -# qhasm: b0_stack = b0 -# asm 1: movq b0_stack=stack64#12 -# asm 2: movq b0_stack=88(%rsp) -movq %r10,88(%rsp) - -# qhasm: b1_stack = b1 -# asm 1: movq b1_stack=stack64#13 -# asm 2: movq b1_stack=96(%rsp) -movq %r11,96(%rsp) - -# qhasm: b2_stack = b2 -# asm 1: movq b2_stack=stack64#14 -# asm 2: movq b2_stack=104(%rsp) -movq %r12,104(%rsp) - -# qhasm: b3_stack = b3 -# asm 1: movq b3_stack=stack64#15 -# asm 2: movq b3_stack=112(%rsp) -movq %r13,112(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = a0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 56(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a0=int64#11 -# asm 2: mov a0=%r13 -mov %rax,%r13 - -# qhasm: a1 = mulrdx -# asm 1: mov a1=int64#12 -# asm 2: mov a1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 8) -# asm 1: movq 8(mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a2=int64#13 -# asm 2: mov $0,>a2=%r15 -mov $0,%r15 - -# qhasm: a2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a3=int64#14 -# asm 2: mov $0,>a3=%rbx -mov $0,%rbx - -# qhasm: a3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 64(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 72(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 80(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? a0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: a0 += mulzero -# asm 1: add a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %r13,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r14,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r15,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %rbx,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = b0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 88(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul e0=int64#11 -# asm 2: mov e0=%r13 -mov %rax,%r13 - -# qhasm: e1 = mulrdx -# asm 1: mov e1=int64#12 -# asm 2: mov e1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 40) -# asm 1: movq 40(mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul e2=int64#13 -# asm 2: mov $0,>e2=%r15 -mov $0,%r15 - -# qhasm: e2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul e3=int64#14 -# asm 2: mov $0,>e3=%rbx -mov $0,%rbx - -# qhasm: e3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 96(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 104(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 112(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? e0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: e0 += mulzero -# asm 1: add h0=int64#3 -# asm 2: mov h0=%rdx -mov %r13,%rdx - -# qhasm: h1 = e1 -# asm 1: mov h1=int64#5 -# asm 2: mov h1=%r8 -mov %r14,%r8 - -# qhasm: h2 = e2 -# asm 1: mov h2=int64#6 -# asm 2: mov h2=%r9 -mov %r15,%r9 - -# qhasm: h3 = e3 -# asm 1: mov h3=int64#7 -# asm 2: mov h3=%rax -mov %rbx,%rax - -# qhasm: carry? e0 -= a0_stack -# asm 1: subq subt0=int64#8 -# asm 2: mov $0,>subt0=%r10 -mov $0,%r10 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#9 -# asm 2: mov $38,>subt1=%r11 -mov $38,%r11 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#8 -# asm 2: mov $0,>addt0=%r10 -mov $0,%r10 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#9 -# asm 2: mov $38,>addt1=%r11 -mov $38,%r11 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulx0=int64#10 -# asm 2: movq 96(mulx0=%r12 -movq 96(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c0=int64#11 -# asm 2: mov c0=%r13 -mov %rax,%r13 - -# qhasm: c1 = mulrdx -# asm 1: mov c1=int64#12 -# asm 2: mov c1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 72) -# asm 1: movq 72(mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c2=int64#13 -# asm 2: mov $0,>c2=%r15 -mov $0,%r15 - -# qhasm: c2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c3=int64#14 -# asm 2: mov $0,>c3=%rbx -mov $0,%rbx - -# qhasm: c3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq 104(mulx1=%r12 -movq 104(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq 112(mulx2=%r12 -movq 112(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq 120(mulx3=%r12 -movq 120(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? c0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: c0 += mulzero -# asm 1: add f0=int64#3 -# asm 2: movq 64(f0=%rdx -movq 64(%rsi),%rdx - -# qhasm: f1 = *(uint64 *)(pp + 72) -# asm 1: movq 72(f1=int64#4 -# asm 2: movq 72(f1=%rcx -movq 72(%rsi),%rcx - -# qhasm: f2 = *(uint64 *)(pp + 80) -# asm 1: movq 80(f2=int64#5 -# asm 2: movq 80(f2=%r8 -movq 80(%rsi),%r8 - -# qhasm: f3 = *(uint64 *)(pp + 88) -# asm 1: movq 88(f3=int64#2 -# asm 2: movq 88(f3=%rsi -movq 88(%rsi),%rsi - -# qhasm: carry? f0 += f0 -# asm 1: add addt0=int64#6 -# asm 2: mov $0,>addt0=%r9 -mov $0,%r9 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#7 -# asm 2: mov $38,>addt1=%rax -mov $38,%rax - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae g0=int64#6 -# asm 2: mov g0=%r9 -mov %rdx,%r9 - -# qhasm: g1 = f1 -# asm 1: mov g1=int64#7 -# asm 2: mov g1=%rax -mov %rcx,%rax - -# qhasm: g2 = f2 -# asm 1: mov g2=int64#8 -# asm 2: mov g2=%r10 -mov %r8,%r10 - -# qhasm: g3 = f3 -# asm 1: mov g3=int64#9 -# asm 2: mov g3=%r11 -mov %rsi,%r11 - -# qhasm: carry? f0 -= c0 -# asm 1: sub subt0=int64#10 -# asm 2: mov $0,>subt0=%r12 -mov $0,%r12 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#15 -# asm 2: mov $38,>subt1=%rbp -mov $38,%rbp - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#10 -# asm 2: mov $0,>addt0=%r12 -mov $0,%r12 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#11 -# asm 2: mov $38,>addt1=%r13 -mov $38,%r13 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.s b/ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.s deleted file mode 100644 index beddbc79..00000000 --- a/ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.s +++ /dev/null @@ -1,2236 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 pp - -# qhasm: input rp - -# qhasm: input pp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 -.globl crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2 -_crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2: -crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p2: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 0) -# asm 1: movq 0(mulx0=int64#9 -# asm 2: movq 0(mulx0=%r11 -movq 0(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx0=int64#10 -# asm 2: mov rx0=%r12 -mov %rax,%r12 - -# qhasm: rx1 = mulrdx -# asm 1: mov rx1=int64#11 -# asm 2: mov rx1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 104) -# asm 1: movq 104(mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx2=int64#12 -# asm 2: mov $0,>rx2=%r14 -mov $0,%r14 - -# qhasm: rx2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx3=int64#13 -# asm 2: mov $0,>rx3=%r15 -mov $0,%r15 - -# qhasm: rx3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 8(mulx1=%r11 -movq 8(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 16(mulx2=%r11 -movq 16(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 24(mulx3=%r11 -movq 24(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? rx0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: rx0 += mulzero -# asm 1: add mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulx0=int64#9 -# asm 2: movq 64(mulx0=%r11 -movq 64(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry0=int64#10 -# asm 2: mov ry0=%r12 -mov %rax,%r12 - -# qhasm: ry1 = mulrdx -# asm 1: mov ry1=int64#11 -# asm 2: mov ry1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 40) -# asm 1: movq 40(mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry2=int64#12 -# asm 2: mov $0,>ry2=%r14 -mov $0,%r14 - -# qhasm: ry2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry3=int64#13 -# asm 2: mov $0,>ry3=%r15 -mov $0,%r15 - -# qhasm: ry3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 72(mulx1=%r11 -movq 72(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 80(mulx2=%r11 -movq 80(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 88(mulx3=%r11 -movq 88(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? ry0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: ry0 += mulzero -# asm 1: add mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulx0=int64#9 -# asm 2: movq 32(mulx0=%r11 -movq 32(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz0=int64#10 -# asm 2: mov rz0=%r12 -mov %rax,%r12 - -# qhasm: rz1 = mulrdx -# asm 1: mov rz1=int64#11 -# asm 2: mov rz1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 104) -# asm 1: movq 104(mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz2=int64#12 -# asm 2: mov $0,>rz2=%r14 -mov $0,%r14 - -# qhasm: rz2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz3=int64#13 -# asm 2: mov $0,>rz3=%r15 -mov $0,%r15 - -# qhasm: rz3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 40(mulx1=%r11 -movq 40(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 48(mulx2=%r11 -movq 48(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 56(mulx3=%r11 -movq 56(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rz0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rz0 += mulzero -# asm 1: add caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.s b/ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.s deleted file mode 100644 index 82433fba..00000000 --- a/ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.s +++ /dev/null @@ -1,2926 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 pp - -# qhasm: input rp - -# qhasm: input pp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 rt0 - -# qhasm: int64 rt1 - -# qhasm: int64 rt2 - -# qhasm: int64 rt3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 -.globl crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3 -_crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3: -crypto_sign_ed25519_amd64_64_ge25519_p1p1_to_p3: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 0) -# asm 1: movq 0(mulx0=int64#9 -# asm 2: movq 0(mulx0=%r11 -movq 0(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx0=int64#10 -# asm 2: mov rx0=%r12 -mov %rax,%r12 - -# qhasm: rx1 = mulrdx -# asm 1: mov rx1=int64#11 -# asm 2: mov rx1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 104) -# asm 1: movq 104(mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx2=int64#12 -# asm 2: mov $0,>rx2=%r14 -mov $0,%r14 - -# qhasm: rx2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx3=int64#13 -# asm 2: mov $0,>rx3=%r15 -mov $0,%r15 - -# qhasm: rx3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 8(mulx1=%r11 -movq 8(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 16(mulx2=%r11 -movq 16(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 24(mulx3=%r11 -movq 24(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? rx0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: rx0 += mulzero -# asm 1: add mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulx0=int64#9 -# asm 2: movq 64(mulx0=%r11 -movq 64(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry0=int64#10 -# asm 2: mov ry0=%r12 -mov %rax,%r12 - -# qhasm: ry1 = mulrdx -# asm 1: mov ry1=int64#11 -# asm 2: mov ry1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 40) -# asm 1: movq 40(mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry2=int64#12 -# asm 2: mov $0,>ry2=%r14 -mov $0,%r14 - -# qhasm: ry2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul ry3=int64#13 -# asm 2: mov $0,>ry3=%r15 -mov $0,%r15 - -# qhasm: ry3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 72(mulx1=%r11 -movq 72(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 80(mulx2=%r11 -movq 80(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 88(mulx3=%r11 -movq 88(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? ry0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: ry0 += mulzero -# asm 1: add mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 32) -# asm 1: movq 32(mulx0=int64#9 -# asm 2: movq 32(mulx0=%r11 -movq 32(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz0=int64#10 -# asm 2: mov rz0=%r12 -mov %rax,%r12 - -# qhasm: rz1 = mulrdx -# asm 1: mov rz1=int64#11 -# asm 2: mov rz1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 104) -# asm 1: movq 104(mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz2=int64#12 -# asm 2: mov $0,>rz2=%r14 -mov $0,%r14 - -# qhasm: rz2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rz3=int64#13 -# asm 2: mov $0,>rz3=%r15 -mov $0,%r15 - -# qhasm: rz3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 40(mulx1=%r11 -movq 40(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 48(mulx2=%r11 -movq 48(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 56(mulx3=%r11 -movq 56(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#4 -# asm 2: mov mulr4=%rcx -mov %rax,%rcx - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#5 -# asm 2: mov mulr5=%r8 -mov %rdx,%r8 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#4 -# asm 2: imulq $38,mulr8=%rcx -imulq $38,%rax,%rcx - -# qhasm: carry? rz0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: rz0 += mulzero -# asm 1: add mulr4=int64#4 -# asm 2: mov $0,>mulr4=%rcx -mov $0,%rcx - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#5 -# asm 2: mov $0,>mulr5=%r8 -mov $0,%r8 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#6 -# asm 2: mov $0,>mulr6=%r9 -mov $0,%r9 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#8 -# asm 2: mov $0,>mulr7=%r10 -mov $0,%r10 - -# qhasm: mulx0 = *(uint64 *)(pp + 0) -# asm 1: movq 0(mulx0=int64#9 -# asm 2: movq 0(mulx0=%r11 -movq 0(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt0=int64#10 -# asm 2: mov rt0=%r12 -mov %rax,%r12 - -# qhasm: rt1 = mulrdx -# asm 1: mov rt1=int64#11 -# asm 2: mov rt1=%r13 -mov %rdx,%r13 - -# qhasm: mulrax = *(uint64 *)(pp + 72) -# asm 1: movq 72(mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt2=int64#12 -# asm 2: mov $0,>rt2=%r14 -mov $0,%r14 - -# qhasm: rt2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt3=int64#13 -# asm 2: mov $0,>rt3=%r15 -mov $0,%r15 - -# qhasm: rt3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#9 -# asm 2: movq 8(mulx1=%r11 -movq 8(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#9 -# asm 2: movq 16(mulx2=%r11 -movq 16(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#9 -# asm 2: movq 24(mulx3=%r11 -movq 24(%rsi),%r11 - -# qhasm: mulrax = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#14 -# asm 2: mov $0,>mulc=%rbx -mov $0,%rbx - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rsi),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %rcx,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rt0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rt0 += mulzero -# asm 1: add caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_pack.c b/ext/ed25519-amd64-asm/ge25519_pack.c deleted file mode 100644 index f289fe57..00000000 --- a/ext/ed25519-amd64-asm/ge25519_pack.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "fe25519.h" -#include "sc25519.h" -#include "ge25519.h" - -void ge25519_pack(unsigned char r[32], const ge25519_p3 *p) -{ - fe25519 tx, ty, zi; - fe25519_invert(&zi, &p->z); - fe25519_mul(&tx, &p->x, &zi); - fe25519_mul(&ty, &p->y, &zi); - fe25519_pack(r, &ty); - r[31] ^= fe25519_getparity(&tx) << 7; -} diff --git a/ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.s b/ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.s deleted file mode 100644 index aff2e75d..00000000 --- a/ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.s +++ /dev/null @@ -1,3662 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 pp - -# qhasm: int64 qp - -# qhasm: input rp - -# qhasm: input pp - -# qhasm: input qp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 a0 - -# qhasm: int64 a1 - -# qhasm: int64 a2 - -# qhasm: int64 a3 - -# qhasm: stack64 a0_stack - -# qhasm: stack64 a1_stack - -# qhasm: stack64 a2_stack - -# qhasm: stack64 a3_stack - -# qhasm: int64 b0 - -# qhasm: int64 b1 - -# qhasm: int64 b2 - -# qhasm: int64 b3 - -# qhasm: stack64 b0_stack - -# qhasm: stack64 b1_stack - -# qhasm: stack64 b2_stack - -# qhasm: stack64 b3_stack - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: stack64 c0_stack - -# qhasm: stack64 c1_stack - -# qhasm: stack64 c2_stack - -# qhasm: stack64 c3_stack - -# qhasm: int64 d0 - -# qhasm: int64 d1 - -# qhasm: int64 d2 - -# qhasm: int64 d3 - -# qhasm: stack64 d0_stack - -# qhasm: stack64 d1_stack - -# qhasm: stack64 d2_stack - -# qhasm: stack64 d3_stack - -# qhasm: int64 t10 - -# qhasm: int64 t11 - -# qhasm: int64 t12 - -# qhasm: int64 t13 - -# qhasm: stack64 t10_stack - -# qhasm: stack64 t11_stack - -# qhasm: stack64 t12_stack - -# qhasm: stack64 t13_stack - -# qhasm: int64 t20 - -# qhasm: int64 t21 - -# qhasm: int64 t22 - -# qhasm: int64 t23 - -# qhasm: stack64 t20_stack - -# qhasm: stack64 t21_stack - -# qhasm: stack64 t22_stack - -# qhasm: stack64 t23_stack - -# qhasm: int64 rx0 - -# qhasm: int64 rx1 - -# qhasm: int64 rx2 - -# qhasm: int64 rx3 - -# qhasm: int64 ry0 - -# qhasm: int64 ry1 - -# qhasm: int64 ry2 - -# qhasm: int64 ry3 - -# qhasm: int64 rz0 - -# qhasm: int64 rz1 - -# qhasm: int64 rz2 - -# qhasm: int64 rz3 - -# qhasm: int64 rt0 - -# qhasm: int64 rt1 - -# qhasm: int64 rt2 - -# qhasm: int64 rt3 - -# qhasm: int64 x0 - -# qhasm: int64 x1 - -# qhasm: int64 x2 - -# qhasm: int64 x3 - -# qhasm: int64 mulr4 - -# qhasm: int64 mulr5 - -# qhasm: int64 mulr6 - -# qhasm: int64 mulr7 - -# qhasm: int64 mulr8 - -# qhasm: int64 mulrax - -# qhasm: int64 mulrdx - -# qhasm: int64 mulx0 - -# qhasm: int64 mulx1 - -# qhasm: int64 mulx2 - -# qhasm: int64 mulx3 - -# qhasm: int64 mulc - -# qhasm: int64 mulzero - -# qhasm: int64 muli38 - -# qhasm: int64 addt0 - -# qhasm: int64 addt1 - -# qhasm: int64 subt0 - -# qhasm: int64 subt1 - -# qhasm: enter crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 -.globl crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1 -_crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1: -crypto_sign_ed25519_amd64_64_ge25519_pnielsadd_p1p1: -mov %rsp,%r11 -and $31,%r11 -add $128,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: qp = qp -# asm 1: mov qp=int64#4 -# asm 2: mov qp=%rcx -mov %rdx,%rcx - -# qhasm: a0 = *(uint64 *)(pp + 32) -# asm 1: movq 32(a0=int64#3 -# asm 2: movq 32(a0=%rdx -movq 32(%rsi),%rdx - -# qhasm: a1 = *(uint64 *)(pp + 40) -# asm 1: movq 40(a1=int64#5 -# asm 2: movq 40(a1=%r8 -movq 40(%rsi),%r8 - -# qhasm: a2 = *(uint64 *)(pp + 48) -# asm 1: movq 48(a2=int64#6 -# asm 2: movq 48(a2=%r9 -movq 48(%rsi),%r9 - -# qhasm: a3 = *(uint64 *)(pp + 56) -# asm 1: movq 56(a3=int64#7 -# asm 2: movq 56(a3=%rax -movq 56(%rsi),%rax - -# qhasm: b0 = a0 -# asm 1: mov b0=int64#8 -# asm 2: mov b0=%r10 -mov %rdx,%r10 - -# qhasm: b1 = a1 -# asm 1: mov b1=int64#9 -# asm 2: mov b1=%r11 -mov %r8,%r11 - -# qhasm: b2 = a2 -# asm 1: mov b2=int64#10 -# asm 2: mov b2=%r12 -mov %r9,%r12 - -# qhasm: b3 = a3 -# asm 1: mov b3=int64#11 -# asm 2: mov b3=%r13 -mov %rax,%r13 - -# qhasm: carry? a0 -= *(uint64 *)(pp + 0) -# asm 1: subq 0(subt0=int64#12 -# asm 2: mov $0,>subt0=%r14 -mov $0,%r14 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#13 -# asm 2: mov $38,>subt1=%r15 -mov $38,%r15 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae addt0=int64#12 -# asm 2: mov $0,>addt0=%r14 -mov $0,%r14 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#13 -# asm 2: mov $38,>addt1=%r15 -mov $38,%r15 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %rdx,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r8,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r9,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %rax,80(%rsp) - -# qhasm: b0_stack = b0 -# asm 1: movq b0_stack=stack64#12 -# asm 2: movq b0_stack=88(%rsp) -movq %r10,88(%rsp) - -# qhasm: b1_stack = b1 -# asm 1: movq b1_stack=stack64#13 -# asm 2: movq b1_stack=96(%rsp) -movq %r11,96(%rsp) - -# qhasm: b2_stack = b2 -# asm 1: movq b2_stack=stack64#14 -# asm 2: movq b2_stack=104(%rsp) -movq %r12,104(%rsp) - -# qhasm: b3_stack = b3 -# asm 1: movq b3_stack=stack64#15 -# asm 2: movq b3_stack=112(%rsp) -movq %r13,112(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = a0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 56(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a0=int64#11 -# asm 2: mov a0=%r13 -mov %rax,%r13 - -# qhasm: a1 = mulrdx -# asm 1: mov a1=int64#12 -# asm 2: mov a1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 8) -# asm 1: movq 8(mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a2=int64#13 -# asm 2: mov $0,>a2=%r15 -mov $0,%r15 - -# qhasm: a2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul a3=int64#14 -# asm 2: mov $0,>a3=%rbx -mov $0,%rbx - -# qhasm: a3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 64(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 72(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 80(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 0) -# asm 1: movq 0(mulrax=int64#7 -# asm 2: movq 0(mulrax=%rax -movq 0(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 8(mulrax=%rax -movq 8(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 16(mulrax=%rax -movq 16(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 24(mulrax=%rax -movq 24(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? a0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: a0 += mulzero -# asm 1: add a0_stack=stack64#8 -# asm 2: movq a0_stack=56(%rsp) -movq %r13,56(%rsp) - -# qhasm: a1_stack = a1 -# asm 1: movq a1_stack=stack64#9 -# asm 2: movq a1_stack=64(%rsp) -movq %r14,64(%rsp) - -# qhasm: a2_stack = a2 -# asm 1: movq a2_stack=stack64#10 -# asm 2: movq a2_stack=72(%rsp) -movq %r15,72(%rsp) - -# qhasm: a3_stack = a3 -# asm 1: movq a3_stack=stack64#11 -# asm 2: movq a3_stack=80(%rsp) -movq %rbx,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = b0_stack -# asm 1: movq mulx0=int64#10 -# asm 2: movq mulx0=%r12 -movq 88(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx0=int64#11 -# asm 2: mov rx0=%r13 -mov %rax,%r13 - -# qhasm: rx1 = mulrdx -# asm 1: mov rx1=int64#12 -# asm 2: mov rx1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 40) -# asm 1: movq 40(mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx2=int64#13 -# asm 2: mov $0,>rx2=%r15 -mov $0,%r15 - -# qhasm: rx2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rx3=int64#14 -# asm 2: mov $0,>rx3=%rbx -mov $0,%rbx - -# qhasm: rx3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq mulx1=%r12 -movq 96(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq mulx2=%r12 -movq 104(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq mulx3=%r12 -movq 112(%rsp),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 32) -# asm 1: movq 32(mulrax=int64#7 -# asm 2: movq 32(mulrax=%rax -movq 32(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 40(mulrax=%rax -movq 40(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 48(mulrax=%rax -movq 48(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 56(mulrax=%rax -movq 56(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? rx0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: rx0 += mulzero -# asm 1: add ry0=int64#3 -# asm 2: mov ry0=%rdx -mov %r13,%rdx - -# qhasm: ry1 = rx1 -# asm 1: mov ry1=int64#5 -# asm 2: mov ry1=%r8 -mov %r14,%r8 - -# qhasm: ry2 = rx2 -# asm 1: mov ry2=int64#6 -# asm 2: mov ry2=%r9 -mov %r15,%r9 - -# qhasm: ry3 = rx3 -# asm 1: mov ry3=int64#7 -# asm 2: mov ry3=%rax -mov %rbx,%rax - -# qhasm: carry? ry0 += a0_stack -# asm 1: addq addt0=int64#8 -# asm 2: mov $0,>addt0=%r10 -mov $0,%r10 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#9 -# asm 2: mov $38,>addt1=%r11 -mov $38,%r11 - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae subt0=int64#8 -# asm 2: mov $0,>subt0=%r10 -mov $0,%r10 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#9 -# asm 2: mov $38,>subt1=%r11 -mov $38,%r11 - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = *(uint64 *)(pp + 96) -# asm 1: movq 96(mulx0=int64#10 -# asm 2: movq 96(mulx0=%r12 -movq 96(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c0=int64#11 -# asm 2: mov c0=%r13 -mov %rax,%r13 - -# qhasm: c1 = mulrdx -# asm 1: mov c1=int64#12 -# asm 2: mov c1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 104) -# asm 1: movq 104(mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c2=int64#13 -# asm 2: mov $0,>c2=%r15 -mov $0,%r15 - -# qhasm: c2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul c3=int64#14 -# asm 2: mov $0,>c3=%rbx -mov $0,%rbx - -# qhasm: c3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq 104(mulx1=%r12 -movq 104(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq 112(mulx2=%r12 -movq 112(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#10 -# asm 2: movq 120(mulx3=%r12 -movq 120(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 96) -# asm 1: movq 96(mulrax=int64#7 -# asm 2: movq 96(mulrax=%rax -movq 96(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 104(mulrax=%rax -movq 104(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 112(mulrax=%rax -movq 112(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 120(mulrax=%rax -movq 120(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#5 -# asm 2: mov mulr4=%r8 -mov %rax,%r8 - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#6 -# asm 2: mov mulr5=%r9 -mov %rdx,%r9 - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#3 -# asm 2: mov $0,>mulzero=%rdx -mov $0,%rdx - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#5 -# asm 2: imulq $38,mulr8=%r8 -imulq $38,%rax,%r8 - -# qhasm: carry? c0 += mulr8 -# asm 1: add mulzero=int64#3 -# asm 2: imulq $38,mulzero=%rdx -imulq $38,%rdx,%rdx - -# qhasm: c0 += mulzero -# asm 1: add c0_stack=stack64#8 -# asm 2: movq c0_stack=56(%rsp) -movq %r13,56(%rsp) - -# qhasm: c1_stack = c1 -# asm 1: movq c1_stack=stack64#9 -# asm 2: movq c1_stack=64(%rsp) -movq %r14,64(%rsp) - -# qhasm: c2_stack = c2 -# asm 1: movq c2_stack=stack64#10 -# asm 2: movq c2_stack=72(%rsp) -movq %r15,72(%rsp) - -# qhasm: c3_stack = c3 -# asm 1: movq c3_stack=stack64#11 -# asm 2: movq c3_stack=80(%rsp) -movq %rbx,80(%rsp) - -# qhasm: mulr4 = 0 -# asm 1: mov $0,>mulr4=int64#5 -# asm 2: mov $0,>mulr4=%r8 -mov $0,%r8 - -# qhasm: mulr5 = 0 -# asm 1: mov $0,>mulr5=int64#6 -# asm 2: mov $0,>mulr5=%r9 -mov $0,%r9 - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#8 -# asm 2: mov $0,>mulr6=%r10 -mov $0,%r10 - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#9 -# asm 2: mov $0,>mulr7=%r11 -mov $0,%r11 - -# qhasm: mulx0 = *(uint64 *)(pp + 64) -# asm 1: movq 64(mulx0=int64#10 -# asm 2: movq 64(mulx0=%r12 -movq 64(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt0=int64#11 -# asm 2: mov rt0=%r13 -mov %rax,%r13 - -# qhasm: rt1 = mulrdx -# asm 1: mov rt1=int64#12 -# asm 2: mov rt1=%r14 -mov %rdx,%r14 - -# qhasm: mulrax = *(uint64 *)(qp + 72) -# asm 1: movq 72(mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt2=int64#13 -# asm 2: mov $0,>rt2=%r15 -mov $0,%r15 - -# qhasm: rt2 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul rt3=int64#14 -# asm 2: mov $0,>rt3=%rbx -mov $0,%rbx - -# qhasm: rt3 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx0 -# asm 1: mul mulx1=int64#10 -# asm 2: movq 72(mulx1=%r12 -movq 72(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx1 -# asm 1: mul mulx2=int64#10 -# asm 2: movq 80(mulx2=%r12 -movq 80(%rsi),%r12 - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulc=int64#15 -# asm 2: mov $0,>mulc=%rbp -mov $0,%rbp - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx2 -# asm 1: mul mulx3=int64#2 -# asm 2: movq 88(mulx3=%rsi -movq 88(%rsi),%rsi - -# qhasm: mulrax = *(uint64 *)(qp + 64) -# asm 1: movq 64(mulrax=int64#7 -# asm 2: movq 64(mulrax=%rax -movq 64(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 72(mulrax=%rax -movq 72(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 80(mulrax=%rax -movq 80(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulc=int64#10 -# asm 2: mov $0,>mulc=%r12 -mov $0,%r12 - -# qhasm: mulc += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: movq 88(mulrax=%rax -movq 88(%rcx),%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * mulx3 -# asm 1: mul mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r8,%rax - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: mulr4 = mulrax -# asm 1: mov mulr4=int64#2 -# asm 2: mov mulr4=%rsi -mov %rax,%rsi - -# qhasm: mulrax = mulr5 -# asm 1: mov mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r9,%rax - -# qhasm: mulr5 = mulrdx -# asm 1: mov mulr5=int64#4 -# asm 2: mov mulr5=%rcx -mov %rdx,%rcx - -# qhasm: (uint128) mulrdx mulrax = mulrax * *(uint64 *)&crypto_sign_ed25519_amd64_64_38 -mulq crypto_sign_ed25519_amd64_64_38(%rip) - -# qhasm: carry? mulr5 += mulrax -# asm 1: add mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r10,%rax - -# qhasm: mulr6 = 0 -# asm 1: mov $0,>mulr6=int64#5 -# asm 2: mov $0,>mulr6=%r8 -mov $0,%r8 - -# qhasm: mulr6 += mulrdx + carry -# asm 1: adc mulrax=int64#7 -# asm 2: mov mulrax=%rax -mov %r11,%rax - -# qhasm: mulr7 = 0 -# asm 1: mov $0,>mulr7=int64#6 -# asm 2: mov $0,>mulr7=%r9 -mov $0,%r9 - -# qhasm: mulr7 += mulrdx + carry -# asm 1: adc mulr8=int64#7 -# asm 2: mov $0,>mulr8=%rax -mov $0,%rax - -# qhasm: mulr8 += mulrdx + carry -# asm 1: adc mulzero=int64#2 -# asm 2: mov $0,>mulzero=%rsi -mov $0,%rsi - -# qhasm: mulr8 += mulzero + carry -# asm 1: adc mulr8=int64#3 -# asm 2: imulq $38,mulr8=%rdx -imulq $38,%rax,%rdx - -# qhasm: carry? rt0 += mulr8 -# asm 1: add mulzero=int64#2 -# asm 2: imulq $38,mulzero=%rsi -imulq $38,%rsi,%rsi - -# qhasm: rt0 += mulzero -# asm 1: add addt0=int64#2 -# asm 2: mov $0,>addt0=%rsi -mov $0,%rsi - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#3 -# asm 2: mov $38,>addt1=%rdx -mov $38,%rdx - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae rz0=int64#2 -# asm 2: mov rz0=%rsi -mov %r13,%rsi - -# qhasm: rz1 = rt1 -# asm 1: mov rz1=int64#3 -# asm 2: mov rz1=%rdx -mov %r14,%rdx - -# qhasm: rz2 = rt2 -# asm 1: mov rz2=int64#4 -# asm 2: mov rz2=%rcx -mov %r15,%rcx - -# qhasm: rz3 = rt3 -# asm 1: mov rz3=int64#5 -# asm 2: mov rz3=%r8 -mov %rbx,%r8 - -# qhasm: carry? rz0 += c0_stack -# asm 1: addq addt0=int64#6 -# asm 2: mov $0,>addt0=%r9 -mov $0,%r9 - -# qhasm: addt1 = 38 -# asm 1: mov $38,>addt1=int64#7 -# asm 2: mov $38,>addt1=%rax -mov $38,%rax - -# qhasm: addt1 = addt0 if !carry -# asm 1: cmovae subt0=int64#6 -# asm 2: mov $0,>subt0=%r9 -mov $0,%r9 - -# qhasm: subt1 = 38 -# asm 1: mov $38,>subt1=int64#7 -# asm 2: mov $38,>subt1=%rax -mov $38,%rax - -# qhasm: subt1 = subt0 if !carry -# asm 1: cmovae caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/ge25519_scalarmult_base.c b/ext/ed25519-amd64-asm/ge25519_scalarmult_base.c deleted file mode 100644 index ffa6e2fa..00000000 --- a/ext/ed25519-amd64-asm/ge25519_scalarmult_base.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "fe25519.h" -#include "sc25519.h" -#include "ge25519.h" - -/* Multiples of the base point in Niels' representation */ -static const ge25519_niels ge25519_base_multiples_niels[] = { -#ifdef SMALLTABLES -#include "ge25519_base_niels_smalltables.data" -#else -#include "ge25519_base_niels.data" -#endif -}; - -/* d */ -/*static const fe25519 ecd = {{0x75EB4DCA135978A3, 0x00700A4D4141D8AB, 0x8CC740797779E898, 0x52036CEE2B6FFE73}};*/ - -void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s) -{ - signed char b[64]; - int i; - ge25519_niels t; - fe25519 d; - - sc25519_window4(b,s); - -#ifdef SMALLTABLES - ge25519_p1p1 tp1p1; - choose_t((ge25519_niels *)r, 0, (signed long long) b[1], ge25519_base_multiples_niels); - fe25519_sub(&d, &r->y, &r->x); - fe25519_add(&r->y, &r->y, &r->x); - r->x = d; - r->t = r->z; - fe25519_setint(&r->z,2); - for(i=3;i<64;i+=2) - { - choose_t(&t, (unsigned long long) i/2, (signed long long) b[i], ge25519_base_multiples_niels); - ge25519_nielsadd2(r, &t); - } - ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); - ge25519_p1p1_to_p2((ge25519_p2 *)r, &tp1p1); - ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); - ge25519_p1p1_to_p2((ge25519_p2 *)r, &tp1p1); - ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); - ge25519_p1p1_to_p2((ge25519_p2 *)r, &tp1p1); - ge25519_dbl_p1p1(&tp1p1,(ge25519_p2 *)r); - ge25519_p1p1_to_p3(r, &tp1p1); - choose_t(&t, (unsigned long long) 0, (signed long long) b[0], ge25519_base_multiples_niels); - fe25519_mul(&t.t2d, &t.t2d, &ecd); - ge25519_nielsadd2(r, &t); - for(i=2;i<64;i+=2) - { - choose_t(&t, (unsigned long long) i/2, (signed long long) b[i], ge25519_base_multiples_niels); - ge25519_nielsadd2(r, &t); - } -#else - choose_t((ge25519_niels *)r, 0, (signed long long) b[0], ge25519_base_multiples_niels); - fe25519_sub(&d, &r->y, &r->x); - fe25519_add(&r->y, &r->y, &r->x); - r->x = d; - r->t = r->z; - fe25519_setint(&r->z,2); - for(i=1;i<64;i++) - { - choose_t(&t, (unsigned long long) i, (signed long long) b[i], ge25519_base_multiples_niels); - ge25519_nielsadd2(r, &t); - } -#endif -} diff --git a/ext/ed25519-amd64-asm/ge25519_unpackneg.c b/ext/ed25519-amd64-asm/ge25519_unpackneg.c deleted file mode 100644 index ff16fd20..00000000 --- a/ext/ed25519-amd64-asm/ge25519_unpackneg.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "fe25519.h" -#include "ge25519.h" - -/* d */ -static const fe25519 ecd = {{0x75EB4DCA135978A3, 0x00700A4D4141D8AB, 0x8CC740797779E898, 0x52036CEE2B6FFE73}}; -/* sqrt(-1) */ -static const fe25519 sqrtm1 = {{0xC4EE1B274A0EA0B0, 0x2F431806AD2FE478, 0x2B4D00993DFBD7A7, 0x2B8324804FC1DF0B}}; - -/* return 0 on success, -1 otherwise */ -int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32]) -{ - fe25519 t, chk, num, den, den2, den4, den6; - unsigned char par = p[31] >> 7; - - fe25519_setint(&r->z,1); - fe25519_unpack(&r->y, p); - fe25519_square(&num, &r->y); /* x = y^2 */ - fe25519_mul(&den, &num, &ecd); /* den = dy^2 */ - fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ - fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ - - /* Computation of sqrt(num/den) - 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) - */ - fe25519_square(&den2, &den); - fe25519_square(&den4, &den2); - fe25519_mul(&den6, &den4, &den2); - fe25519_mul(&t, &den6, &num); - fe25519_mul(&t, &t, &den); - - fe25519_pow2523(&t, &t); - /* 2. computation of r->x = t * num * den^3 - */ - fe25519_mul(&t, &t, &num); - fe25519_mul(&t, &t, &den); - fe25519_mul(&t, &t, &den); - fe25519_mul(&r->x, &t, &den); - - /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: - */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) - fe25519_mul(&r->x, &r->x, &sqrtm1); - - /* 4. Now we have one of the two square roots, except if input was not a square - */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) - return -1; - - /* 5. Choose the desired square root according to parity: - */ - if(fe25519_getparity(&r->x) != (1-par)) - fe25519_neg(&r->x, &r->x); - - fe25519_mul(&r->t, &r->x, &r->y); - return 0; -} diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced.s b/ext/ed25519-amd64-asm/heap_rootreplaced.s deleted file mode 100644 index 8fe385b4..00000000 --- a/ext/ed25519-amd64-asm/heap_rootreplaced.s +++ /dev/null @@ -1,476 +0,0 @@ - -# qhasm: int64 hp - -# qhasm: int64 hlen - -# qhasm: int64 sp - -# qhasm: int64 pp - -# qhasm: input hp - -# qhasm: input hlen - -# qhasm: input sp - -# qhasm: int64 prc - -# qhasm: int64 plc - -# qhasm: int64 pc - -# qhasm: int64 d - -# qhasm: int64 spp - -# qhasm: int64 sprc - -# qhasm: int64 spc - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 p0 - -# qhasm: int64 p1 - -# qhasm: int64 p2 - -# qhasm: int64 p3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced -.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced -_crypto_sign_ed25519_amd64_64_heap_rootreplaced: -crypto_sign_ed25519_amd64_64_heap_rootreplaced: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: pp = 0 -# asm 1: mov $0,>pp=int64#4 -# asm 2: mov $0,>pp=%rcx -mov $0,%rcx - -# qhasm: siftdownloop: -._siftdownloop: - -# qhasm: prc = pp -# asm 1: mov prc=int64#5 -# asm 2: mov prc=%r8 -mov %rcx,%r8 - -# qhasm: prc *= 2 -# asm 1: imulq $2,prc=int64#5 -# asm 2: imulq $2,prc=%r8 -imulq $2,%r8,%r8 - -# qhasm: pc = prc -# asm 1: mov pc=int64#6 -# asm 2: mov pc=%r9 -mov %r8,%r9 - -# qhasm: prc += 2 -# asm 1: add $2,? hlen - prc -# asm 1: cmp -jbe ._siftuploop - -# qhasm: sprc = *(uint64 *)(hp + prc * 8) -# asm 1: movq (sprc=int64#7 -# asm 2: movq (sprc=%rax -movq (%rdi,%r8,8),%rax - -# qhasm: sprc <<= 5 -# asm 1: shl $5,spc=int64#8 -# asm 2: movq (spc=%r10 -movq (%rdi,%r9,8),%r10 - -# qhasm: spc <<= 5 -# asm 1: shl $5,c0=int64#9 -# asm 2: movq 0(c0=%r11 -movq 0(%r10),%r11 - -# qhasm: c1 = *(uint64 *)(spc + 8) -# asm 1: movq 8(c1=int64#10 -# asm 2: movq 8(c1=%r12 -movq 8(%r10),%r12 - -# qhasm: c2 = *(uint64 *)(spc + 16) -# asm 1: movq 16(c2=int64#11 -# asm 2: movq 16(c2=%r13 -movq 16(%r10),%r13 - -# qhasm: c3 = *(uint64 *)(spc + 24) -# asm 1: movq 24(c3=int64#12 -# asm 2: movq 24(c3=%r14 -movq 24(%r10),%r14 - -# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: *(uint64 *)(hp + pp * 8) = spc -# asm 1: movq pp=int64#4 -# asm 2: mov pp=%rcx -mov %r9,%rcx -# comment:fp stack unchanged by jump - -# qhasm: goto siftdownloop -jmp ._siftdownloop - -# qhasm: siftuploop: -._siftuploop: - -# qhasm: pc = pp -# asm 1: mov pc=int64#2 -# asm 2: mov pc=%rsi -mov %rcx,%rsi - -# qhasm: pp -= 1 -# asm 1: sub $1,>= 1 -# asm 1: shr $1,? pc - 0 -# asm 1: cmp $0, -jbe ._end - -# qhasm: spp = *(uint64 *)(hp + pp * 8) -# asm 1: movq (spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: spc = *(uint64 *)(hp + pc * 8) -# asm 1: movq (spc=int64#6 -# asm 2: movq (spc=%r9 -movq (%rdi,%rsi,8),%r9 - -# qhasm: spp <<= 5 -# asm 1: shl $5,c0=int64#7 -# asm 2: movq 0(c0=%rax -movq 0(%r9),%rax - -# qhasm: c1 = *(uint64 *)(spc + 8) -# asm 1: movq 8(c1=int64#8 -# asm 2: movq 8(c1=%r10 -movq 8(%r9),%r10 - -# qhasm: c2 = *(uint64 *)(spc + 16) -# asm 1: movq 16(c2=int64#9 -# asm 2: movq 16(c2=%r11 -movq 16(%r9),%r11 - -# qhasm: c3 = *(uint64 *)(spc + 24) -# asm 1: movq 24(c3=int64#10 -# asm 2: movq 24(c3=%r12 -movq 24(%r9),%r12 - -# qhasm: carry? c0 -= *(uint64 *)(spp + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,>= 5 -# asm 1: shr $5,caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced_1limb.s b/ext/ed25519-amd64-asm/heap_rootreplaced_1limb.s deleted file mode 100644 index 488e9c52..00000000 --- a/ext/ed25519-amd64-asm/heap_rootreplaced_1limb.s +++ /dev/null @@ -1,416 +0,0 @@ - -# qhasm: int64 hp - -# qhasm: int64 hlen - -# qhasm: int64 sp - -# qhasm: int64 pp - -# qhasm: input hp - -# qhasm: input hlen - -# qhasm: input sp - -# qhasm: int64 prc - -# qhasm: int64 plc - -# qhasm: int64 pc - -# qhasm: int64 d - -# qhasm: int64 spp - -# qhasm: int64 sprc - -# qhasm: int64 spc - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 p0 - -# qhasm: int64 p1 - -# qhasm: int64 p2 - -# qhasm: int64 p3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb -.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb -_crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb: -crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: pp = 0 -# asm 1: mov $0,>pp=int64#4 -# asm 2: mov $0,>pp=%rcx -mov $0,%rcx - -# qhasm: siftdownloop: -._siftdownloop: - -# qhasm: prc = pp -# asm 1: mov prc=int64#5 -# asm 2: mov prc=%r8 -mov %rcx,%r8 - -# qhasm: prc *= 2 -# asm 1: imulq $2,prc=int64#5 -# asm 2: imulq $2,prc=%r8 -imulq $2,%r8,%r8 - -# qhasm: pc = prc -# asm 1: mov pc=int64#6 -# asm 2: mov pc=%r9 -mov %r8,%r9 - -# qhasm: prc += 2 -# asm 1: add $2,? hlen - prc -# asm 1: cmp -jbe ._siftuploop - -# qhasm: sprc = *(uint64 *)(hp + prc * 8) -# asm 1: movq (sprc=int64#7 -# asm 2: movq (sprc=%rax -movq (%rdi,%r8,8),%rax - -# qhasm: sprc <<= 5 -# asm 1: shl $5,spc=int64#8 -# asm 2: movq (spc=%r10 -movq (%rdi,%r9,8),%r10 - -# qhasm: spc <<= 5 -# asm 1: shl $5,c0=int64#9 -# asm 2: movq 0(c0=%r11 -movq 0(%r10),%r11 - -# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: *(uint64 *)(hp + pp * 8) = spc -# asm 1: movq pp=int64#4 -# asm 2: mov pp=%rcx -mov %r9,%rcx -# comment:fp stack unchanged by jump - -# qhasm: goto siftdownloop -jmp ._siftdownloop - -# qhasm: siftuploop: -._siftuploop: - -# qhasm: pc = pp -# asm 1: mov pc=int64#2 -# asm 2: mov pc=%rsi -mov %rcx,%rsi - -# qhasm: pp -= 1 -# asm 1: sub $1,>= 1 -# asm 1: shr $1,? pc - 0 -# asm 1: cmp $0, -jbe ._end - -# qhasm: spp = *(uint64 *)(hp + pp * 8) -# asm 1: movq (spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: spc = *(uint64 *)(hp + pc * 8) -# asm 1: movq (spc=int64#6 -# asm 2: movq (spc=%r9 -movq (%rdi,%rsi,8),%r9 - -# qhasm: spp <<= 5 -# asm 1: shl $5,c0=int64#7 -# asm 2: movq 0(c0=%rax -movq 0(%r9),%rax - -# qhasm: carry? c0 -= *(uint64 *)(spp + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,>= 5 -# asm 1: shr $5,caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.s b/ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.s deleted file mode 100644 index f9259184..00000000 --- a/ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.s +++ /dev/null @@ -1,436 +0,0 @@ - -# qhasm: int64 hp - -# qhasm: int64 hlen - -# qhasm: int64 sp - -# qhasm: int64 pp - -# qhasm: input hp - -# qhasm: input hlen - -# qhasm: input sp - -# qhasm: int64 prc - -# qhasm: int64 plc - -# qhasm: int64 pc - -# qhasm: int64 d - -# qhasm: int64 spp - -# qhasm: int64 sprc - -# qhasm: int64 spc - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 p0 - -# qhasm: int64 p1 - -# qhasm: int64 p2 - -# qhasm: int64 p3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs -.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs -_crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs: -crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: pp = 0 -# asm 1: mov $0,>pp=int64#4 -# asm 2: mov $0,>pp=%rcx -mov $0,%rcx - -# qhasm: siftdownloop: -._siftdownloop: - -# qhasm: prc = pp -# asm 1: mov prc=int64#5 -# asm 2: mov prc=%r8 -mov %rcx,%r8 - -# qhasm: prc *= 2 -# asm 1: imulq $2,prc=int64#5 -# asm 2: imulq $2,prc=%r8 -imulq $2,%r8,%r8 - -# qhasm: pc = prc -# asm 1: mov pc=int64#6 -# asm 2: mov pc=%r9 -mov %r8,%r9 - -# qhasm: prc += 2 -# asm 1: add $2,? hlen - prc -# asm 1: cmp -jbe ._siftuploop - -# qhasm: sprc = *(uint64 *)(hp + prc * 8) -# asm 1: movq (sprc=int64#7 -# asm 2: movq (sprc=%rax -movq (%rdi,%r8,8),%rax - -# qhasm: sprc <<= 5 -# asm 1: shl $5,spc=int64#8 -# asm 2: movq (spc=%r10 -movq (%rdi,%r9,8),%r10 - -# qhasm: spc <<= 5 -# asm 1: shl $5,c0=int64#9 -# asm 2: movq 0(c0=%r11 -movq 0(%r10),%r11 - -# qhasm: c1 = *(uint64 *)(spc + 8) -# asm 1: movq 8(c1=int64#10 -# asm 2: movq 8(c1=%r12 -movq 8(%r10),%r12 - -# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: *(uint64 *)(hp + pp * 8) = spc -# asm 1: movq pp=int64#4 -# asm 2: mov pp=%rcx -mov %r9,%rcx -# comment:fp stack unchanged by jump - -# qhasm: goto siftdownloop -jmp ._siftdownloop - -# qhasm: siftuploop: -._siftuploop: - -# qhasm: pc = pp -# asm 1: mov pc=int64#2 -# asm 2: mov pc=%rsi -mov %rcx,%rsi - -# qhasm: pp -= 1 -# asm 1: sub $1,>= 1 -# asm 1: shr $1,? pc - 0 -# asm 1: cmp $0, -jbe ._end - -# qhasm: spp = *(uint64 *)(hp + pp * 8) -# asm 1: movq (spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: spc = *(uint64 *)(hp + pc * 8) -# asm 1: movq (spc=int64#6 -# asm 2: movq (spc=%r9 -movq (%rdi,%rsi,8),%r9 - -# qhasm: spp <<= 5 -# asm 1: shl $5,c0=int64#7 -# asm 2: movq 0(c0=%rax -movq 0(%r9),%rax - -# qhasm: c1 = *(uint64 *)(spc + 8) -# asm 1: movq 8(c1=int64#8 -# asm 2: movq 8(c1=%r10 -movq 8(%r9),%r10 - -# qhasm: carry? c0 -= *(uint64 *)(spp + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,>= 5 -# asm 1: shr $5,caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.s b/ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.s deleted file mode 100644 index dcf890ea..00000000 --- a/ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.s +++ /dev/null @@ -1,456 +0,0 @@ - -# qhasm: int64 hp - -# qhasm: int64 hlen - -# qhasm: int64 sp - -# qhasm: int64 pp - -# qhasm: input hp - -# qhasm: input hlen - -# qhasm: input sp - -# qhasm: int64 prc - -# qhasm: int64 plc - -# qhasm: int64 pc - -# qhasm: int64 d - -# qhasm: int64 spp - -# qhasm: int64 sprc - -# qhasm: int64 spc - -# qhasm: int64 c0 - -# qhasm: int64 c1 - -# qhasm: int64 c2 - -# qhasm: int64 c3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 p0 - -# qhasm: int64 p1 - -# qhasm: int64 p2 - -# qhasm: int64 p3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs -.globl crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs -_crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs: -crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: pp = 0 -# asm 1: mov $0,>pp=int64#4 -# asm 2: mov $0,>pp=%rcx -mov $0,%rcx - -# qhasm: siftdownloop: -._siftdownloop: - -# qhasm: prc = pp -# asm 1: mov prc=int64#5 -# asm 2: mov prc=%r8 -mov %rcx,%r8 - -# qhasm: prc *= 2 -# asm 1: imulq $2,prc=int64#5 -# asm 2: imulq $2,prc=%r8 -imulq $2,%r8,%r8 - -# qhasm: pc = prc -# asm 1: mov pc=int64#6 -# asm 2: mov pc=%r9 -mov %r8,%r9 - -# qhasm: prc += 2 -# asm 1: add $2,? hlen - prc -# asm 1: cmp -jbe ._siftuploop - -# qhasm: sprc = *(uint64 *)(hp + prc * 8) -# asm 1: movq (sprc=int64#7 -# asm 2: movq (sprc=%rax -movq (%rdi,%r8,8),%rax - -# qhasm: sprc <<= 5 -# asm 1: shl $5,spc=int64#8 -# asm 2: movq (spc=%r10 -movq (%rdi,%r9,8),%r10 - -# qhasm: spc <<= 5 -# asm 1: shl $5,c0=int64#9 -# asm 2: movq 0(c0=%r11 -movq 0(%r10),%r11 - -# qhasm: c1 = *(uint64 *)(spc + 8) -# asm 1: movq 8(c1=int64#10 -# asm 2: movq 8(c1=%r12 -movq 8(%r10),%r12 - -# qhasm: c2 = *(uint64 *)(spc + 16) -# asm 1: movq 16(c2=int64#11 -# asm 2: movq 16(c2=%r13 -movq 16(%r10),%r13 - -# qhasm: carry? c0 -= *(uint64 *)(sprc + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: *(uint64 *)(hp + pp * 8) = spc -# asm 1: movq pp=int64#4 -# asm 2: mov pp=%rcx -mov %r9,%rcx -# comment:fp stack unchanged by jump - -# qhasm: goto siftdownloop -jmp ._siftdownloop - -# qhasm: siftuploop: -._siftuploop: - -# qhasm: pc = pp -# asm 1: mov pc=int64#2 -# asm 2: mov pc=%rsi -mov %rcx,%rsi - -# qhasm: pp -= 1 -# asm 1: sub $1,>= 1 -# asm 1: shr $1,? pc - 0 -# asm 1: cmp $0, -jbe ._end - -# qhasm: spp = *(uint64 *)(hp + pp * 8) -# asm 1: movq (spp=int64#5 -# asm 2: movq (spp=%r8 -movq (%rdi,%rcx,8),%r8 - -# qhasm: spc = *(uint64 *)(hp + pc * 8) -# asm 1: movq (spc=int64#6 -# asm 2: movq (spc=%r9 -movq (%rdi,%rsi,8),%r9 - -# qhasm: spp <<= 5 -# asm 1: shl $5,c0=int64#7 -# asm 2: movq 0(c0=%rax -movq 0(%r9),%rax - -# qhasm: c1 = *(uint64 *)(spc + 8) -# asm 1: movq 8(c1=int64#8 -# asm 2: movq 8(c1=%r10 -movq 8(%r9),%r10 - -# qhasm: c2 = *(uint64 *)(spc + 16) -# asm 1: movq 16(c2=int64#9 -# asm 2: movq 16(c2=%r11 -movq 16(%r9),%r11 - -# qhasm: carry? c0 -= *(uint64 *)(spp + 0) -# asm 1: subq 0(>= 5 -# asm 1: shr $5,>= 5 -# asm 1: shr $5,caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/hram.c b/ext/ed25519-amd64-asm/hram.c deleted file mode 100644 index 6f99fc62..00000000 --- a/ext/ed25519-amd64-asm/hram.c +++ /dev/null @@ -1,16 +0,0 @@ -/*#include "crypto_hash_sha512.h"*/ -#include "hram.h" - -extern void ZT_sha512internal(void *digest,const void *data,unsigned int len); - -void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen) -{ - unsigned long long i; - - for (i = 0;i < 32;++i) playground[i] = sm[i]; - for (i = 32;i < 64;++i) playground[i] = pk[i-32]; - for (i = 64;i < smlen;++i) playground[i] = sm[i]; - - /*crypto_hash_sha512(hram,playground,smlen);*/ - ZT_sha512internal(hram,playground,smlen); -} diff --git a/ext/ed25519-amd64-asm/hram.h b/ext/ed25519-amd64-asm/hram.h deleted file mode 100644 index 1740c78a..00000000 --- a/ext/ed25519-amd64-asm/hram.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef HRAM_H -#define HRAM_H - -#define get_hram crypto_sign_ed25519_amd64_64_get_hram - -extern void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen); - -#endif diff --git a/ext/ed25519-amd64-asm/implementors b/ext/ed25519-amd64-asm/implementors deleted file mode 100644 index 9b5399a3..00000000 --- a/ext/ed25519-amd64-asm/implementors +++ /dev/null @@ -1,5 +0,0 @@ -Daniel J. Bernstein -Niels Duif -Tanja Lange -lead: Peter Schwabe -Bo-Yin Yang diff --git a/ext/ed25519-amd64-asm/index_heap.c b/ext/ed25519-amd64-asm/index_heap.c deleted file mode 100644 index f29f7a28..00000000 --- a/ext/ed25519-amd64-asm/index_heap.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "sc25519.h" -#include "index_heap.h" - -/* caller's responsibility to ensure hlen>=3 */ -void heap_init(unsigned long long *h, unsigned long long hlen, sc25519 *scalars) -{ - h[0] = 0; - unsigned long long i=1; - while(i 0) - { - /* if(sc25519_lt_vartime(&scalars[h[ppos]], &scalars[h[pos]])) */ - if(sc25519_lt(&scalars[h[ppos]], &scalars[h[pos]])) - { - t = h[ppos]; - h[ppos] = h[pos]; - h[pos] = t; - pos = ppos; - ppos = (pos-1)/2; - } - else break; - } - (*hlen)++; -} - -/* Put the largest value in the heap in max1, the second largest in max2 */ -void heap_get2max(unsigned long long *h, unsigned long long *max1, unsigned long long *max2, sc25519 *scalars) -{ - *max1 = h[0]; - *max2 = h[1]; - if(sc25519_lt(&scalars[h[1]],&scalars[h[2]])) - *max2 = h[2]; -} - -/* After the root has been replaced, restore heap property */ -/* extern void heap_rootreplaced(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); -*/ -/* extern void heap_rootreplaced_shortscalars(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); -*/ diff --git a/ext/ed25519-amd64-asm/index_heap.h b/ext/ed25519-amd64-asm/index_heap.h deleted file mode 100644 index 7dee9161..00000000 --- a/ext/ed25519-amd64-asm/index_heap.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef INDEX_HEAP_H -#define INDEX_HEAP_H - -#include "sc25519.h" - -#define heap_init crypto_sign_ed25519_amd64_64_heap_init -#define heap_extend crypto_sign_ed25519_amd64_64_heap_extend -#define heap_pop crypto_sign_ed25519_amd64_64_heap_pop -#define heap_push crypto_sign_ed25519_amd64_64_heap_push -#define heap_get2max crypto_sign_ed25519_amd64_64_heap_get2max -#define heap_rootreplaced crypto_sign_ed25519_amd64_64_heap_rootreplaced -#define heap_rootreplaced_3limbs crypto_sign_ed25519_amd64_64_heap_rootreplaced_3limbs -#define heap_rootreplaced_2limbs crypto_sign_ed25519_amd64_64_heap_rootreplaced_2limbs -#define heap_rootreplaced_1limb crypto_sign_ed25519_amd64_64_heap_rootreplaced_1limb - -void heap_init(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); - -void heap_extend(unsigned long long *h, unsigned long long oldlen, unsigned long long newlen, sc25519 *scalars); - -unsigned long long heap_pop(unsigned long long *h, unsigned long long *hlen, sc25519 *scalars); - -void heap_push(unsigned long long *h, unsigned long long *hlen, unsigned long long elem, sc25519 *scalars); - -void heap_get2max(unsigned long long *h, unsigned long long *max1, unsigned long long *max2, sc25519 *scalars); - -void heap_rootreplaced(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); -void heap_rootreplaced_3limbs(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); -void heap_rootreplaced_2limbs(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); -void heap_rootreplaced_1limb(unsigned long long *h, unsigned long long hlen, sc25519 *scalars); - -#endif diff --git a/ext/ed25519-amd64-asm/keypair.c b/ext/ed25519-amd64-asm/keypair.c deleted file mode 100644 index 7e094710..00000000 --- a/ext/ed25519-amd64-asm/keypair.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include "crypto_sign.h" -#include "crypto_hash_sha512.h" -#include "randombytes.h" -#include "ge25519.h" - -int crypto_sign_keypair(unsigned char *pk,unsigned char *sk) -{ - unsigned char az[64]; - sc25519 scsk; - ge25519 gepk; - - randombytes(sk,32); - crypto_hash_sha512(az,sk,32); - az[0] &= 248; - az[31] &= 127; - az[31] |= 64; - - sc25519_from32bytes(&scsk,az); - - ge25519_scalarmult_base(&gepk, &scsk); - ge25519_pack(pk, &gepk); - memmove(sk + 32,pk,32); - return 0; -} diff --git a/ext/ed25519-amd64-asm/open.c b/ext/ed25519-amd64-asm/open.c deleted file mode 100644 index 104d48dc..00000000 --- a/ext/ed25519-amd64-asm/open.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include "crypto_sign.h" -#include "crypto_verify_32.h" -#include "crypto_hash_sha512.h" -#include "ge25519.h" - -int crypto_sign_open( - unsigned char *m,unsigned long long *mlen, - const unsigned char *sm,unsigned long long smlen, - const unsigned char *pk - ) -{ - unsigned char pkcopy[32]; - unsigned char rcopy[32]; - unsigned char hram[64]; - unsigned char rcheck[32]; - ge25519 get1, get2; - sc25519 schram, scs; - - if (smlen < 64) goto badsig; - if (sm[63] & 224) goto badsig; - if (ge25519_unpackneg_vartime(&get1,pk)) goto badsig; - - memmove(pkcopy,pk,32); - memmove(rcopy,sm,32); - - sc25519_from32bytes(&scs, sm+32); - - memmove(m,sm,smlen); - memmove(m + 32,pkcopy,32); - crypto_hash_sha512(hram,m,smlen); - - sc25519_from64bytes(&schram, hram); - - ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &scs); - ge25519_pack(rcheck, &get2); - - if (crypto_verify_32(rcopy,rcheck) == 0) { - memmove(m,m + 64,smlen - 64); - memset(m + smlen - 64,0,64); - *mlen = smlen - 64; - return 0; - } - -badsig: - *mlen = (unsigned long long) -1; - memset(m,0,smlen); - return -1; -} diff --git a/ext/ed25519-amd64-asm/sc25519.h b/ext/ed25519-amd64-asm/sc25519.h deleted file mode 100644 index 8ff1b1ca..00000000 --- a/ext/ed25519-amd64-asm/sc25519.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef SC25519_H -#define SC25519_H - -#define sc25519 crypto_sign_ed25519_amd64_64_sc25519 -#define shortsc25519 crypto_sign_ed25519_amd64_64_shortsc25519 -#define sc25519_from32bytes crypto_sign_ed25519_amd64_64_sc25519_from32bytes -#define shortsc25519_from16bytes crypto_sign_ed25519_amd64_64_shortsc25519_from16bytes -#define sc25519_from64bytes crypto_sign_ed25519_amd64_64_sc25519_from64bytes -#define sc25519_from_shortsc crypto_sign_ed25519_amd64_64_sc25519_from_shortsc -#define sc25519_to32bytes crypto_sign_ed25519_amd64_64_sc25519_to32bytes -#define sc25519_iszero_vartime crypto_sign_ed25519_amd64_64_sc25519_iszero_vartime -#define sc25519_isshort_vartime crypto_sign_ed25519_amd64_64_sc25519_isshort_vartime -#define sc25519_lt crypto_sign_ed25519_amd64_64_sc25519_lt -#define sc25519_add crypto_sign_ed25519_amd64_64_sc25519_add -#define sc25519_sub_nored crypto_sign_ed25519_amd64_64_sc25519_sub_nored -#define sc25519_mul crypto_sign_ed25519_amd64_64_sc25519_mul -#define sc25519_mul_shortsc crypto_sign_ed25519_amd64_64_sc25519_mul_shortsc -#define sc25519_window4 crypto_sign_ed25519_amd64_64_sc25519_window4 -#define sc25519_slide crypto_sign_ed25519_amd64_64_sc25519_slide -#define sc25519_2interleave2 crypto_sign_ed25519_amd64_64_sc25519_2interleave2 -#define sc25519_barrett crypto_sign_ed25519_amd64_64_sc25519_barrett - -typedef struct -{ - unsigned long long v[4]; -} -sc25519; - -typedef struct -{ - unsigned long long v[2]; -} -shortsc25519; - -void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]); - -void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]); - -void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x); - -void sc25519_to32bytes(unsigned char r[32], const sc25519 *x); - -int sc25519_iszero_vartime(const sc25519 *x); - -int sc25519_lt(const sc25519 *x, const sc25519 *y); - -void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y); - -void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y); - -void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y); - -void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y); - -/* Convert s into a representation of the form \sum_{i=0}^{63}r[i]2^(4*i) - * with r[i] in {-8,...,7} - */ -void sc25519_window4(signed char r[85], const sc25519 *s); - -void sc25519_slide(signed char r[256], const sc25519 *s, int swindowsize); - -void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2); - -void sc25519_barrett(sc25519 *r, unsigned long long x[8]); - -#endif diff --git a/ext/ed25519-amd64-asm/sc25519_add.s b/ext/ed25519-amd64-asm/sc25519_add.s deleted file mode 100644 index d5b941cd..00000000 --- a/ext/ed25519-amd64-asm/sc25519_add.s +++ /dev/null @@ -1,232 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_add -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_sc25519_add -.globl crypto_sign_ed25519_amd64_64_sc25519_add -_crypto_sign_ed25519_amd64_64_sc25519_add: -crypto_sign_ed25519_amd64_64_sc25519_add: -mov %rsp,%r11 -and $31,%r11 -add $32,%r11 -sub %r11,%rsp - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#1 -# asm 2: movq caller4_stack=0(%rsp) -movq %r14,0(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#2 -# asm 2: movq caller5_stack=8(%rsp) -movq %r15,8(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#3 -# asm 2: movq caller6_stack=16(%rsp) -movq %rbx,16(%rsp) - -# qhasm: r0 = *(uint64 *)(xp + 0) -# asm 1: movq 0(r0=int64#4 -# asm 2: movq 0(r0=%rcx -movq 0(%rsi),%rcx - -# qhasm: r1 = *(uint64 *)(xp + 8) -# asm 1: movq 8(r1=int64#5 -# asm 2: movq 8(r1=%r8 -movq 8(%rsi),%r8 - -# qhasm: r2 = *(uint64 *)(xp + 16) -# asm 1: movq 16(r2=int64#6 -# asm 2: movq 16(r2=%r9 -movq 16(%rsi),%r9 - -# qhasm: r3 = *(uint64 *)(xp + 24) -# asm 1: movq 24(r3=int64#2 -# asm 2: movq 24(r3=%rsi -movq 24(%rsi),%rsi - -# qhasm: carry? r0 += *(uint64 *)(yp + 0) -# asm 1: addq 0(t0=int64#3 -# asm 2: mov t0=%rdx -mov %rcx,%rdx - -# qhasm: t1 = r1 -# asm 1: mov t1=int64#7 -# asm 2: mov t1=%rax -mov %r8,%rax - -# qhasm: t2 = r2 -# asm 1: mov t2=int64#8 -# asm 2: mov t2=%r10 -mov %r9,%r10 - -# qhasm: t3 = r3 -# asm 1: mov t3=int64#12 -# asm 2: mov t3=%r14 -mov %rsi,%r14 - -# qhasm: carry? t0 -= *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -# asm 1: sub crypto_sign_ed25519_amd64_64_ORDER0,caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 0(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 8(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 16(%rsp),%rbx - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/sc25519_barrett.s b/ext/ed25519-amd64-asm/sc25519_barrett.s deleted file mode 100644 index 7eb56fad..00000000 --- a/ext/ed25519-amd64-asm/sc25519_barrett.s +++ /dev/null @@ -1,1188 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: int64 q23 - -# qhasm: int64 q24 - -# qhasm: int64 q30 - -# qhasm: int64 q31 - -# qhasm: int64 q32 - -# qhasm: int64 q33 - -# qhasm: int64 r20 - -# qhasm: int64 r21 - -# qhasm: int64 r22 - -# qhasm: int64 r23 - -# qhasm: int64 r24 - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 rax - -# qhasm: int64 rdx - -# qhasm: int64 c - -# qhasm: int64 zero - -# qhasm: int64 mask - -# qhasm: int64 nmask - -# qhasm: stack64 q30_stack - -# qhasm: stack64 q31_stack - -# qhasm: stack64 q32_stack - -# qhasm: stack64 q33_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_barrett -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_sc25519_barrett -.globl crypto_sign_ed25519_amd64_64_sc25519_barrett -_crypto_sign_ed25519_amd64_64_sc25519_barrett: -crypto_sign_ed25519_amd64_64_sc25519_barrett: -mov %rsp,%r11 -and $31,%r11 -add $96,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: zero ^= zero -# asm 1: xor rax=int64#7 -# asm 2: movq 24(rax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 -mulq crypto_sign_ed25519_amd64_64_MU3(%rip) - -# qhasm: q23 = rax -# asm 1: mov q23=int64#10 -# asm 2: mov q23=%r12 -mov %rax,%r12 - -# qhasm: c = rdx -# asm 1: mov c=int64#11 -# asm 2: mov c=%r13 -mov %rdx,%r13 - -# qhasm: rax = *(uint64 *)(xp + 24) -# asm 1: movq 24(rax=int64#7 -# asm 2: movq 24(rax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 -mulq crypto_sign_ed25519_amd64_64_MU4(%rip) - -# qhasm: q24 = rax -# asm 1: mov q24=int64#12 -# asm 2: mov q24=%r14 -mov %rax,%r14 - -# qhasm: carry? q24 += c -# asm 1: add rax=int64#7 -# asm 2: movq 32(rax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 -mulq crypto_sign_ed25519_amd64_64_MU2(%rip) - -# qhasm: carry? q23 += rax -# asm 1: add c=int64#11 -# asm 2: mov $0,>c=%r13 -mov $0,%r13 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 32(rax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 -mulq crypto_sign_ed25519_amd64_64_MU3(%rip) - -# qhasm: carry? q24 += rax -# asm 1: add c=int64#11 -# asm 2: mov $0,>c=%r13 -mov $0,%r13 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 32(rax=%rax -movq 32(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 -mulq crypto_sign_ed25519_amd64_64_MU4(%rip) - -# qhasm: carry? q30 += rax -# asm 1: add rax=int64#7 -# asm 2: movq 40(rax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU1 -mulq crypto_sign_ed25519_amd64_64_MU1(%rip) - -# qhasm: carry? q23 += rax -# asm 1: add c=int64#11 -# asm 2: mov $0,>c=%r13 -mov $0,%r13 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 40(rax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 -mulq crypto_sign_ed25519_amd64_64_MU2(%rip) - -# qhasm: carry? q24 += rax -# asm 1: add c=int64#11 -# asm 2: mov $0,>c=%r13 -mov $0,%r13 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 40(rax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 -mulq crypto_sign_ed25519_amd64_64_MU3(%rip) - -# qhasm: carry? q30 += rax -# asm 1: add c=int64#11 -# asm 2: mov $0,>c=%r13 -mov $0,%r13 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 40(rax=%rax -movq 40(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 -mulq crypto_sign_ed25519_amd64_64_MU4(%rip) - -# qhasm: carry? q31 += rax -# asm 1: add rax=int64#7 -# asm 2: movq 48(rax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU0 -mulq crypto_sign_ed25519_amd64_64_MU0(%rip) - -# qhasm: carry? q23 += rax -# asm 1: add c=int64#10 -# asm 2: mov $0,>c=%r12 -mov $0,%r12 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 48(rax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU1 -mulq crypto_sign_ed25519_amd64_64_MU1(%rip) - -# qhasm: carry? q24 += rax -# asm 1: add c=int64#10 -# asm 2: mov $0,>c=%r12 -mov $0,%r12 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 48(rax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 -mulq crypto_sign_ed25519_amd64_64_MU2(%rip) - -# qhasm: carry? q30 += rax -# asm 1: add c=int64#10 -# asm 2: mov $0,>c=%r12 -mov $0,%r12 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 48(rax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 -mulq crypto_sign_ed25519_amd64_64_MU3(%rip) - -# qhasm: carry? q31 += rax -# asm 1: add c=int64#10 -# asm 2: mov $0,>c=%r12 -mov $0,%r12 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 48(rax=%rax -movq 48(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 -mulq crypto_sign_ed25519_amd64_64_MU4(%rip) - -# qhasm: carry? q32 += rax -# asm 1: add rax=int64#7 -# asm 2: movq 56(rax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU0 -mulq crypto_sign_ed25519_amd64_64_MU0(%rip) - -# qhasm: carry? q24 += rax -# asm 1: add c=int64#10 -# asm 2: mov $0,>c=%r12 -mov $0,%r12 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 56(rax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU1 -mulq crypto_sign_ed25519_amd64_64_MU1(%rip) - -# qhasm: carry? q30 += rax -# asm 1: add c=int64#10 -# asm 2: mov $0,>c=%r12 -mov $0,%r12 - -# qhasm: c += rdx + carry -# asm 1: adc q30_stack=stack64#8 -# asm 2: movq q30_stack=56(%rsp) -movq %r8,56(%rsp) - -# qhasm: rax = *(uint64 *)(xp + 56) -# asm 1: movq 56(rax=int64#7 -# asm 2: movq 56(rax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU2 -mulq crypto_sign_ed25519_amd64_64_MU2(%rip) - -# qhasm: carry? q31 += rax -# asm 1: add c=int64#5 -# asm 2: mov $0,>c=%r8 -mov $0,%r8 - -# qhasm: c += rdx + carry -# asm 1: adc q31_stack=stack64#9 -# asm 2: movq q31_stack=64(%rsp) -movq %r9,64(%rsp) - -# qhasm: rax = *(uint64 *)(xp + 56) -# asm 1: movq 56(rax=int64#7 -# asm 2: movq 56(rax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU3 -mulq crypto_sign_ed25519_amd64_64_MU3(%rip) - -# qhasm: carry? q32 += rax -# asm 1: add c=int64#5 -# asm 2: mov $0,>c=%r8 -mov $0,%r8 - -# qhasm: c += rdx + carry -# asm 1: adc q32_stack=stack64#10 -# asm 2: movq q32_stack=72(%rsp) -movq %r10,72(%rsp) - -# qhasm: rax = *(uint64 *)(xp + 56) -# asm 1: movq 56(rax=int64#7 -# asm 2: movq 56(rax=%rax -movq 56(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_MU4 -mulq crypto_sign_ed25519_amd64_64_MU4(%rip) - -# qhasm: carry? q33 += rax -# asm 1: add q33_stack=stack64#11 -# asm 2: movq q33_stack=80(%rsp) -movq %r11,80(%rsp) - -# qhasm: rax = q30_stack -# asm 1: movq rax=int64#7 -# asm 2: movq rax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) - -# qhasm: r20 = rax -# asm 1: mov r20=int64#5 -# asm 2: mov r20=%r8 -mov %rax,%r8 - -# qhasm: c = rdx -# asm 1: mov c=int64#6 -# asm 2: mov c=%r9 -mov %rdx,%r9 - -# qhasm: rax = q30_stack -# asm 1: movq rax=int64#7 -# asm 2: movq rax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER1 -mulq crypto_sign_ed25519_amd64_64_ORDER1(%rip) - -# qhasm: r21 = rax -# asm 1: mov r21=int64#8 -# asm 2: mov r21=%r10 -mov %rax,%r10 - -# qhasm: carry? r21 += c -# asm 1: add c=int64#6 -# asm 2: mov $0,>c=%r9 -mov $0,%r9 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq rax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER2 -mulq crypto_sign_ed25519_amd64_64_ORDER2(%rip) - -# qhasm: r22 = rax -# asm 1: mov r22=int64#9 -# asm 2: mov r22=%r11 -mov %rax,%r11 - -# qhasm: carry? r22 += c -# asm 1: add c=int64#6 -# asm 2: mov $0,>c=%r9 -mov $0,%r9 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq rax=%rax -movq 56(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER3 -mulq crypto_sign_ed25519_amd64_64_ORDER3(%rip) - -# qhasm: free rdx - -# qhasm: r23 = rax -# asm 1: mov r23=int64#10 -# asm 2: mov r23=%r12 -mov %rax,%r12 - -# qhasm: r23 += c -# asm 1: add rax=int64#7 -# asm 2: movq rax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) - -# qhasm: carry? r21 += rax -# asm 1: add c=int64#6 -# asm 2: mov $0,>c=%r9 -mov $0,%r9 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq rax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER1 -mulq crypto_sign_ed25519_amd64_64_ORDER1(%rip) - -# qhasm: carry? r22 += rax -# asm 1: add c=int64#4 -# asm 2: mov $0,>c=%rcx -mov $0,%rcx - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq rax=%rax -movq 64(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER2 -mulq crypto_sign_ed25519_amd64_64_ORDER2(%rip) - -# qhasm: free rdx - -# qhasm: r23 += rax -# asm 1: add rax=int64#7 -# asm 2: movq rax=%rax -movq 72(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) - -# qhasm: carry? r22 += rax -# asm 1: add c=int64#4 -# asm 2: mov $0,>c=%rcx -mov $0,%rcx - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq rax=%rax -movq 72(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER1 -mulq crypto_sign_ed25519_amd64_64_ORDER1(%rip) - -# qhasm: free rdx - -# qhasm: r23 += rax -# asm 1: add rax=int64#7 -# asm 2: movq rax=%rax -movq 80(%rsp),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -mulq crypto_sign_ed25519_amd64_64_ORDER0(%rip) - -# qhasm: free rdx - -# qhasm: r23 += rax -# asm 1: add r0=int64#3 -# asm 2: movq 0(r0=%rdx -movq 0(%rsi),%rdx - -# qhasm: carry? r0 -= r20 -# asm 1: sub t0=int64#4 -# asm 2: mov t0=%rcx -mov %rdx,%rcx - -# qhasm: r1 = *(uint64 *)(xp + 8) -# asm 1: movq 8(r1=int64#5 -# asm 2: movq 8(r1=%r8 -movq 8(%rsi),%r8 - -# qhasm: carry? r1 -= r21 - carry -# asm 1: sbb t1=int64#6 -# asm 2: mov t1=%r9 -mov %r8,%r9 - -# qhasm: r2 = *(uint64 *)(xp + 16) -# asm 1: movq 16(r2=int64#7 -# asm 2: movq 16(r2=%rax -movq 16(%rsi),%rax - -# qhasm: carry? r2 -= r22 - carry -# asm 1: sbb t2=int64#8 -# asm 2: mov t2=%r10 -mov %rax,%r10 - -# qhasm: r3 = *(uint64 *)(xp + 24) -# asm 1: movq 24(r3=int64#2 -# asm 2: movq 24(r3=%rsi -movq 24(%rsi),%rsi - -# qhasm: r3 -= r23 - carry -# asm 1: sbb t3=int64#9 -# asm 2: mov t3=%r11 -mov %rsi,%r11 - -# qhasm: carry? t0 -= *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -# asm 1: sub crypto_sign_ed25519_amd64_64_ORDER0,t0=int64#4 -# asm 2: mov t0=%rcx -mov %rdx,%rcx - -# qhasm: r1 = t1 if !unsigned< -# asm 1: cmovae t1=int64#6 -# asm 2: mov t1=%r9 -mov %r8,%r9 - -# qhasm: r2 = t2 if !unsigned< -# asm 1: cmovae t2=int64#8 -# asm 2: mov t2=%r10 -mov %rax,%r10 - -# qhasm: r3 = t3 if !unsigned< -# asm 1: cmovae t3=int64#9 -# asm 2: mov t3=%r11 -mov %rsi,%r11 - -# qhasm: carry? t0 -= *(uint64 *) &crypto_sign_ed25519_amd64_64_ORDER0 -# asm 1: sub crypto_sign_ed25519_amd64_64_ORDER0,caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/ed25519-amd64-asm/sc25519_from32bytes.c b/ext/ed25519-amd64-asm/sc25519_from32bytes.c deleted file mode 100644 index 7f21e686..00000000 --- a/ext/ed25519-amd64-asm/sc25519_from32bytes.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "sc25519.h" - -/*Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 - * = 7237005577332262213973186563042994240857116359379907606001950938285454250989 - */ - -/* Contains order, 2*order, 4*order, 8*order, each represented in 4 consecutive unsigned long long */ -static const unsigned long long order[16] = {0x5812631A5CF5D3EDULL, 0x14DEF9DEA2F79CD6ULL, - 0x0000000000000000ULL, 0x1000000000000000ULL, - 0xB024C634B9EBA7DAULL, 0x29BDF3BD45EF39ACULL, - 0x0000000000000000ULL, 0x2000000000000000ULL, - 0x60498C6973D74FB4ULL, 0x537BE77A8BDE7359ULL, - 0x0000000000000000ULL, 0x4000000000000000ULL, - 0xC09318D2E7AE9F68ULL, 0xA6F7CEF517BCE6B2ULL, - 0x0000000000000000ULL, 0x8000000000000000ULL}; - -static unsigned long long smaller(unsigned long long a,unsigned long long b) -{ - unsigned long long atop = a >> 32; - unsigned long long abot = a & 4294967295; - unsigned long long btop = b >> 32; - unsigned long long bbot = b & 4294967295; - unsigned long long atopbelowbtop = (atop - btop) >> 63; - unsigned long long atopeqbtop = ((atop ^ btop) - 1) >> 63; - unsigned long long abotbelowbbot = (abot - bbot) >> 63; - return atopbelowbtop | (atopeqbtop & abotbelowbbot); -} - -void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]) -{ - unsigned long long t[4]; - unsigned long long b; - unsigned long long mask; - int i, j; - - /* assuming little-endian */ - r->v[0] = *(unsigned long long *)x; - r->v[1] = *(((unsigned long long *)x)+1); - r->v[2] = *(((unsigned long long *)x)+2); - r->v[3] = *(((unsigned long long *)x)+3); - - for(j=3;j>=0;j--) - { - b=0; - for(i=0;i<4;i++) - { - b += order[4*j+i]; /* no overflow for this particular order */ - t[i] = r->v[i] - b; - b = smaller(r->v[i],b); - } - mask = b - 1; - for(i=0;i<4;i++) - r->v[i] ^= mask & (r->v[i] ^ t[i]); - } -} diff --git a/ext/ed25519-amd64-asm/sc25519_from64bytes.c b/ext/ed25519-amd64-asm/sc25519_from64bytes.c deleted file mode 100644 index 8e76a1b3..00000000 --- a/ext/ed25519-amd64-asm/sc25519_from64bytes.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "sc25519.h" - -void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]) -{ - /* assuming little-endian representation of unsigned long long */ - sc25519_barrett(r, (unsigned long long *)x); -} diff --git a/ext/ed25519-amd64-asm/sc25519_from_shortsc.c b/ext/ed25519-amd64-asm/sc25519_from_shortsc.c deleted file mode 100644 index 3b8ff2fb..00000000 --- a/ext/ed25519-amd64-asm/sc25519_from_shortsc.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "sc25519.h" - -void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x) -{ - r->v[0] = x->v[0]; - r->v[1] = x->v[1]; - r->v[2] = 0; - r->v[3] = 0; -} diff --git a/ext/ed25519-amd64-asm/sc25519_iszero.c b/ext/ed25519-amd64-asm/sc25519_iszero.c deleted file mode 100644 index 21f593d7..00000000 --- a/ext/ed25519-amd64-asm/sc25519_iszero.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "sc25519.h" - -int sc25519_iszero_vartime(const sc25519 *x) -{ - if(x->v[0] != 0) return 0; - if(x->v[1] != 0) return 0; - if(x->v[2] != 0) return 0; - if(x->v[3] != 0) return 0; - return 1; -} diff --git a/ext/ed25519-amd64-asm/sc25519_lt.s b/ext/ed25519-amd64-asm/sc25519_lt.s deleted file mode 100644 index 3ba43178..00000000 --- a/ext/ed25519-amd64-asm/sc25519_lt.s +++ /dev/null @@ -1,131 +0,0 @@ - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: int64 ret - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: output ret - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 doof - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_lt -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_sc25519_lt -.globl crypto_sign_ed25519_amd64_64_sc25519_lt -_crypto_sign_ed25519_amd64_64_sc25519_lt: -crypto_sign_ed25519_amd64_64_sc25519_lt: -mov %rsp,%r11 -and $31,%r11 -add $0,%r11 -sub %r11,%rsp - -# qhasm: t0 = *(uint64 *)(xp + 0) -# asm 1: movq 0(t0=int64#3 -# asm 2: movq 0(t0=%rdx -movq 0(%rdi),%rdx - -# qhasm: t1 = *(uint64 *)(xp + 8) -# asm 1: movq 8(t1=int64#4 -# asm 2: movq 8(t1=%rcx -movq 8(%rdi),%rcx - -# qhasm: t2 = *(uint64 *)(xp + 16) -# asm 1: movq 16(t2=int64#5 -# asm 2: movq 16(t2=%r8 -movq 16(%rdi),%r8 - -# qhasm: t3 = *(uint64 *)(xp + 24) -# asm 1: movq 24(t3=int64#1 -# asm 2: movq 24(t3=%rdi -movq 24(%rdi),%rdi - -# qhasm: carry? t0 -= *(uint64 *)(yp + 0) -# asm 1: subq 0(ret=int64#1 -# asm 2: mov $0,>ret=%rdi -mov $0,%rdi - -# qhasm: doof = 1 -# asm 1: mov $1,>doof=int64#2 -# asm 2: mov $1,>doof=%rsi -mov $1,%rsi - -# qhasm: ret = doof if carry -# asm 1: cmovc v, y->v); - sc25519_barrett(r, t); -} diff --git a/ext/ed25519-amd64-asm/sc25519_mul_shortsc.c b/ext/ed25519-amd64-asm/sc25519_mul_shortsc.c deleted file mode 100644 index 0c67250d..00000000 --- a/ext/ed25519-amd64-asm/sc25519_mul_shortsc.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "sc25519.h" - -void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y) -{ - /* XXX: This wants to be faster */ - sc25519 t; - sc25519_from_shortsc(&t, y); - sc25519_mul(r, x, &t); -} diff --git a/ext/ed25519-amd64-asm/sc25519_slide.c b/ext/ed25519-amd64-asm/sc25519_slide.c deleted file mode 100644 index 4e52010d..00000000 --- a/ext/ed25519-amd64-asm/sc25519_slide.c +++ /dev/null @@ -1,49 +0,0 @@ -#include "sc25519.h" - -void sc25519_slide(signed char r[256], const sc25519 *s, int swindowsize) -{ - int i,j,k,b,m=(1<<(swindowsize-1))-1, soplen=256; - unsigned long long sv0 = s->v[0]; - unsigned long long sv1 = s->v[1]; - unsigned long long sv2 = s->v[2]; - unsigned long long sv3 = s->v[3]; - - /* first put the binary expansion into r */ - for(i=0;i<64;i++) { - r[i] = sv0 & 1; - r[i+64] = sv1 & 1; - r[i+128] = sv2 & 1; - r[i+192] = sv3 & 1; - sv0 >>= 1; - sv1 >>= 1; - sv2 >>= 1; - sv3 >>= 1; - } - - /* Making it sliding window */ - for (j = 0;j < soplen;++j) - { - if (r[j]) { - for (b = 1;b < soplen - j && b <= 6;++b) { - if (r[j] + (r[j + b] << b) <= m) - { - r[j] += r[j + b] << b; r[j + b] = 0; - } - else if (r[j] - (r[j + b] << b) >= -m) - { - r[j] -= r[j + b] << b; - for (k = j + b;k < soplen;++k) - { - if (!r[k]) { - r[k] = 1; - break; - } - r[k] = 0; - } - } - else if (r[j + b]) - break; - } - } - } -} diff --git a/ext/ed25519-amd64-asm/sc25519_sub_nored.s b/ext/ed25519-amd64-asm/sc25519_sub_nored.s deleted file mode 100644 index a347e7d4..00000000 --- a/ext/ed25519-amd64-asm/sc25519_sub_nored.s +++ /dev/null @@ -1,142 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 t0 - -# qhasm: int64 t1 - -# qhasm: int64 t2 - -# qhasm: int64 t3 - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_sc25519_sub_nored -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_sc25519_sub_nored -.globl crypto_sign_ed25519_amd64_64_sc25519_sub_nored -_crypto_sign_ed25519_amd64_64_sc25519_sub_nored: -crypto_sign_ed25519_amd64_64_sc25519_sub_nored: -mov %rsp,%r11 -and $31,%r11 -add $0,%r11 -sub %r11,%rsp - -# qhasm: r0 = *(uint64 *)(xp + 0) -# asm 1: movq 0(r0=int64#4 -# asm 2: movq 0(r0=%rcx -movq 0(%rsi),%rcx - -# qhasm: r1 = *(uint64 *)(xp + 8) -# asm 1: movq 8(r1=int64#5 -# asm 2: movq 8(r1=%r8 -movq 8(%rsi),%r8 - -# qhasm: r2 = *(uint64 *)(xp + 16) -# asm 1: movq 16(r2=int64#6 -# asm 2: movq 16(r2=%r9 -movq 16(%rsi),%r9 - -# qhasm: r3 = *(uint64 *)(xp + 24) -# asm 1: movq 24(r3=int64#2 -# asm 2: movq 24(r3=%rsi -movq 24(%rsi),%rsi - -# qhasm: carry? r0 -= *(uint64 *)(yp + 0) -# asm 1: subq 0(v]; -} diff --git a/ext/ed25519-amd64-asm/sc25519_window4.c b/ext/ed25519-amd64-asm/sc25519_window4.c deleted file mode 100644 index 683a1d4b..00000000 --- a/ext/ed25519-amd64-asm/sc25519_window4.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "sc25519.h" - -void sc25519_window4(signed char r[64], const sc25519 *s) -{ - char carry; - int i; - for(i=0;i<16;i++) - r[i] = (s->v[0] >> (4*i)) & 15; - for(i=0;i<16;i++) - r[i+16] = (s->v[1] >> (4*i)) & 15; - for(i=0;i<16;i++) - r[i+32] = (s->v[2] >> (4*i)) & 15; - for(i=0;i<16;i++) - r[i+48] = (s->v[3] >> (4*i)) & 15; - - /* Making it signed */ - carry = 0; - for(i=0;i<63;i++) - { - r[i] += carry; - r[i+1] += r[i] >> 4; - r[i] &= 15; - carry = r[i] >> 3; - r[i] -= carry << 4; - } - r[63] += carry; -} diff --git a/ext/ed25519-amd64-asm/sign.c b/ext/ed25519-amd64-asm/sign.c deleted file mode 100644 index 882ae76f..00000000 --- a/ext/ed25519-amd64-asm/sign.c +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include -/*#include "crypto_sign.h" -#include "crypto_hash_sha512.h"*/ -#include "ge25519.h" - -/* Original */ -#if 0 -int crypto_sign( - unsigned char *sm,unsigned long long *smlen, - const unsigned char *m,unsigned long long mlen, - const unsigned char *sk - ) -{ - unsigned char pk[32]; - unsigned char az[64]; - unsigned char nonce[64]; - unsigned char hram[64]; - sc25519 sck, scs, scsk; - ge25519 ger; - - memmove(pk,sk + 32,32); - /* pk: 32-byte public key A */ - - crypto_hash_sha512(az,sk,32); - az[0] &= 248; - az[31] &= 127; - az[31] |= 64; - /* az: 32-byte scalar a, 32-byte randomizer z */ - - *smlen = mlen + 64; - memmove(sm + 64,m,mlen); - memmove(sm + 32,az + 32,32); - /* sm: 32-byte uninit, 32-byte z, mlen-byte m */ - - crypto_hash_sha512(nonce, sm+32, mlen+32); - /* nonce: 64-byte H(z,m) */ - - sc25519_from64bytes(&sck, nonce); - ge25519_scalarmult_base(&ger, &sck); - ge25519_pack(sm, &ger); - /* sm: 32-byte R, 32-byte z, mlen-byte m */ - - memmove(sm + 32,pk,32); - /* sm: 32-byte R, 32-byte A, mlen-byte m */ - - crypto_hash_sha512(hram,sm,mlen + 64); - /* hram: 64-byte H(R,A,m) */ - - sc25519_from64bytes(&scs, hram); - sc25519_from32bytes(&scsk, az); - sc25519_mul(&scs, &scs, &scsk); - sc25519_add(&scs, &scs, &sck); - /* scs: S = nonce + H(R,A,m)a */ - - sc25519_to32bytes(sm + 32,&scs); - /* sm: 32-byte R, 32-byte S, mlen-byte m */ - - return 0; -} -#endif - -#if 0 -void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature) -{ - sc25519 sck, scs, scsk; - ge25519 ger; - unsigned char r[32]; - unsigned char s[32]; - unsigned char extsk[64]; - unsigned char hmg[crypto_hash_sha512_BYTES]; - unsigned char hram[crypto_hash_sha512_BYTES]; - unsigned char *sig = (unsigned char *)signature; - unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) - - SHA512::hash(digest,msg,len); - - SHA512::hash(extsk,myPrivate.data + 32,32); - extsk[0] &= 248; - extsk[31] &= 127; - extsk[31] |= 64; - - for(unsigned int i=0;i<32;i++) - sig[32 + i] = extsk[32 + i]; - for(unsigned int i=0;i<32;i++) - sig[64 + i] = digest[i]; - - SHA512::hash(hmg,sig + 32,64); - - /* Computation of R */ - sc25519_from64bytes(&sck, hmg); - ge25519_scalarmult_base(&ger, &sck); - ge25519_pack(r, &ger); - - /* Computation of s */ - for(unsigned int i=0;i<32;i++) - sig[i] = r[i]; - - get_hram(hram,sig,myPublic.data + 32,sig,96); - - sc25519_from64bytes(&scs, hram); - sc25519_from32bytes(&scsk, extsk); - sc25519_mul(&scs, &scs, &scsk); - - sc25519_add(&scs, &scs, &sck); - - sc25519_to32bytes(s,&scs); /* cat s */ - for(unsigned int i=0;i<32;i++) - sig[32 + i] = s[i]; -} - -void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen) -{ - unsigned long long i; - - for (i = 0;i < 32;++i) playground[i] = sm[i]; - for (i = 32;i < 64;++i) playground[i] = pk[i-32]; - for (i = 64;i < smlen;++i) playground[i] = sm[i]; - - //crypto_hash_sha512(hram,playground,smlen); - ZeroTier::SHA512::hash(hram,playground,(unsigned int)smlen); -} -#endif - -extern void ZT_sha512internal(void *digest,const void *data,unsigned int len); - -extern void ed25519_amd64_asm_sign(const unsigned char *sk,const unsigned char *pk,const unsigned char *digest,unsigned char *sig) -{ - unsigned char az[64]; - unsigned char nonce[64]; - unsigned char hram[64]; - sc25519 sck, scs, scsk; - ge25519 ger; - unsigned int i; - - ZT_sha512internal(az,sk,32); - az[0] &= 248; - az[31] &= 127; - az[31] |= 64; - - for(i=0;i<32;i++) - sig[32 + i] = az[32 + i]; - for(i=0;i<32;i++) - sig[64 + i] = digest[i]; - - ZT_sha512internal(nonce,sig + 32,64); - - sc25519_from64bytes(&sck, nonce); - ge25519_scalarmult_base(&ger, &sck); - ge25519_pack(sig, &ger); - - memmove(sig + 32,pk,32); - - ZT_sha512internal(hram,sig,96); - - sc25519_from64bytes(&scs, hram); - sc25519_from32bytes(&scsk, az); - sc25519_mul(&scs, &scs, &scsk); - sc25519_add(&scs, &scs, &sck); - - sc25519_to32bytes(sig + 32,&scs); -} diff --git a/ext/ed25519-amd64-asm/ull4_mul.s b/ext/ed25519-amd64-asm/ull4_mul.s deleted file mode 100644 index 9f7b4fa2..00000000 --- a/ext/ed25519-amd64-asm/ull4_mul.s +++ /dev/null @@ -1,716 +0,0 @@ - -# qhasm: int64 rp - -# qhasm: int64 xp - -# qhasm: int64 yp - -# qhasm: input rp - -# qhasm: input xp - -# qhasm: input yp - -# qhasm: int64 r0 - -# qhasm: int64 r1 - -# qhasm: int64 r2 - -# qhasm: int64 r3 - -# qhasm: int64 r4 - -# qhasm: int64 r5 - -# qhasm: int64 r6 - -# qhasm: int64 r7 - -# qhasm: int64 c - -# qhasm: int64 zero - -# qhasm: int64 rax - -# qhasm: int64 rdx - -# qhasm: int64 caller1 - -# qhasm: int64 caller2 - -# qhasm: int64 caller3 - -# qhasm: int64 caller4 - -# qhasm: int64 caller5 - -# qhasm: int64 caller6 - -# qhasm: int64 caller7 - -# qhasm: caller caller1 - -# qhasm: caller caller2 - -# qhasm: caller caller3 - -# qhasm: caller caller4 - -# qhasm: caller caller5 - -# qhasm: caller caller6 - -# qhasm: caller caller7 - -# qhasm: stack64 caller1_stack - -# qhasm: stack64 caller2_stack - -# qhasm: stack64 caller3_stack - -# qhasm: stack64 caller4_stack - -# qhasm: stack64 caller5_stack - -# qhasm: stack64 caller6_stack - -# qhasm: stack64 caller7_stack - -# qhasm: enter crypto_sign_ed25519_amd64_64_ull4_mul -.text -.p2align 5 -.globl _crypto_sign_ed25519_amd64_64_ull4_mul -.globl crypto_sign_ed25519_amd64_64_ull4_mul -_crypto_sign_ed25519_amd64_64_ull4_mul: -crypto_sign_ed25519_amd64_64_ull4_mul: -mov %rsp,%r11 -and $31,%r11 -add $64,%r11 -sub %r11,%rsp - -# qhasm: caller1_stack = caller1 -# asm 1: movq caller1_stack=stack64#1 -# asm 2: movq caller1_stack=0(%rsp) -movq %r11,0(%rsp) - -# qhasm: caller2_stack = caller2 -# asm 1: movq caller2_stack=stack64#2 -# asm 2: movq caller2_stack=8(%rsp) -movq %r12,8(%rsp) - -# qhasm: caller3_stack = caller3 -# asm 1: movq caller3_stack=stack64#3 -# asm 2: movq caller3_stack=16(%rsp) -movq %r13,16(%rsp) - -# qhasm: caller4_stack = caller4 -# asm 1: movq caller4_stack=stack64#4 -# asm 2: movq caller4_stack=24(%rsp) -movq %r14,24(%rsp) - -# qhasm: caller5_stack = caller5 -# asm 1: movq caller5_stack=stack64#5 -# asm 2: movq caller5_stack=32(%rsp) -movq %r15,32(%rsp) - -# qhasm: caller6_stack = caller6 -# asm 1: movq caller6_stack=stack64#6 -# asm 2: movq caller6_stack=40(%rsp) -movq %rbx,40(%rsp) - -# qhasm: caller7_stack = caller7 -# asm 1: movq caller7_stack=stack64#7 -# asm 2: movq caller7_stack=48(%rsp) -movq %rbp,48(%rsp) - -# qhasm: yp = yp -# asm 1: mov yp=int64#4 -# asm 2: mov yp=%rcx -mov %rdx,%rcx - -# qhasm: r4 = 0 -# asm 1: mov $0,>r4=int64#5 -# asm 2: mov $0,>r4=%r8 -mov $0,%r8 - -# qhasm: r5 = 0 -# asm 1: mov $0,>r5=int64#6 -# asm 2: mov $0,>r5=%r9 -mov $0,%r9 - -# qhasm: r6 = 0 -# asm 1: mov $0,>r6=int64#8 -# asm 2: mov $0,>r6=%r10 -mov $0,%r10 - -# qhasm: r7 = 0 -# asm 1: mov $0,>r7=int64#9 -# asm 2: mov $0,>r7=%r11 -mov $0,%r11 - -# qhasm: zero = 0 -# asm 1: mov $0,>zero=int64#10 -# asm 2: mov $0,>zero=%r12 -mov $0,%r12 - -# qhasm: rax = *(uint64 *)(xp + 0) -# asm 1: movq 0(rax=int64#7 -# asm 2: movq 0(rax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) -# asm 1: mulq 0(r0=int64#11 -# asm 2: mov r0=%r13 -mov %rax,%r13 - -# qhasm: c = rdx -# asm 1: mov c=int64#12 -# asm 2: mov c=%r14 -mov %rdx,%r14 - -# qhasm: rax = *(uint64 *)(xp + 0) -# asm 1: movq 0(rax=int64#7 -# asm 2: movq 0(rax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) -# asm 1: mulq 8(r1=int64#13 -# asm 2: mov r1=%r15 -mov %rax,%r15 - -# qhasm: carry? r1 += c -# asm 1: add c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 0(rax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) -# asm 1: mulq 16(r2=int64#14 -# asm 2: mov r2=%rbx -mov %rax,%rbx - -# qhasm: carry? r2 += c -# asm 1: add c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 0(rax=%rax -movq 0(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) -# asm 1: mulq 24(r3=int64#15 -# asm 2: mov r3=%rbp -mov %rax,%rbp - -# qhasm: carry? r3 += c -# asm 1: add rax=int64#7 -# asm 2: movq 8(rax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) -# asm 1: mulq 0(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 8(rax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) -# asm 1: mulq 8(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 8(rax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) -# asm 1: mulq 16(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 8(rax=%rax -movq 8(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) -# asm 1: mulq 24(rax=int64#7 -# asm 2: movq 16(rax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) -# asm 1: mulq 0(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 16(rax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) -# asm 1: mulq 8(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 16(rax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) -# asm 1: mulq 16(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 16(rax=%rax -movq 16(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) -# asm 1: mulq 24(rax=int64#7 -# asm 2: movq 24(rax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 0) -# asm 1: mulq 0(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 24(rax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 8) -# asm 1: mulq 8(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 24(rax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 16) -# asm 1: mulq 16(c=int64#12 -# asm 2: mov $0,>c=%r14 -mov $0,%r14 - -# qhasm: c += rdx + carry -# asm 1: adc rax=int64#7 -# asm 2: movq 24(rax=%rax -movq 24(%rsi),%rax - -# qhasm: (uint128) rdx rax = rax * *(uint64 *)(yp + 24) -# asm 1: mulq 24(caller1=int64#9 -# asm 2: movq caller1=%r11 -movq 0(%rsp),%r11 - -# qhasm: caller2 = caller2_stack -# asm 1: movq caller2=int64#10 -# asm 2: movq caller2=%r12 -movq 8(%rsp),%r12 - -# qhasm: caller3 = caller3_stack -# asm 1: movq caller3=int64#11 -# asm 2: movq caller3=%r13 -movq 16(%rsp),%r13 - -# qhasm: caller4 = caller4_stack -# asm 1: movq caller4=int64#12 -# asm 2: movq caller4=%r14 -movq 24(%rsp),%r14 - -# qhasm: caller5 = caller5_stack -# asm 1: movq caller5=int64#13 -# asm 2: movq caller5=%r15 -movq 32(%rsp),%r15 - -# qhasm: caller6 = caller6_stack -# asm 1: movq caller6=int64#14 -# asm 2: movq caller6=%rbx -movq 40(%rsp),%rbx - -# qhasm: caller7 = caller7_stack -# asm 1: movq caller7=int64#15 -# asm 2: movq caller7=%rbp -movq 48(%rsp),%rbp - -# qhasm: leave -add %r11,%rsp -mov %rdi,%rax -mov %rsi,%rdx -ret diff --git a/ext/hiredis-0.14.1/.gitignore b/ext/hiredis-0.14.1/.gitignore deleted file mode 100644 index db2ad032..00000000 --- a/ext/hiredis-0.14.1/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/hiredis-test -/examples/hiredis-example* -/*.o -/*.so -/*.dylib -/*.pc diff --git a/ext/hiredis-0.14.1/.travis.yml b/ext/hiredis-0.14.1/.travis.yml deleted file mode 100644 index faf2ce68..00000000 --- a/ext/hiredis-0.14.1/.travis.yml +++ /dev/null @@ -1,45 +0,0 @@ -language: c -sudo: false -compiler: - - gcc - - clang - -os: - - linux - - osx - -branches: - only: - - staging - - trying - - master - -before_script: - - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi - -addons: - apt: - packages: - - libc6-dbg - - libc6-dev - - libc6:i386 - - libc6-dev-i386 - - libc6-dbg:i386 - - gcc-multilib - - valgrind - -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" - -matrix: - exclude: - - os: osx - env: PRE="valgrind --track-origins=yes --leak-check=full" - - - os: osx - env: TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" - -script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example diff --git a/ext/hiredis-0.14.1/CHANGELOG.md b/ext/hiredis-0.14.1/CHANGELOG.md deleted file mode 100644 index f8e57736..00000000 --- a/ext/hiredis-0.14.1/CHANGELOG.md +++ /dev/null @@ -1,190 +0,0 @@ -**NOTE: BREAKING CHANGES upgrading from 0.13.x to 0.14.x **: - -* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now - protocol errors. This is consistent with the RESP specification. On 32-bit - platforms, the upper bound is lowered to `SIZE_MAX`. - -* Change `redisReply.len` to `size_t`, as it denotes the the size of a string - - User code should compare this to `size_t` values as well. If it was used to - compare to other values, casting might be necessary or can be removed, if - casting was applied before. - -### 0.14.1 (2020-03-13) - -* Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder) - -### 0.14.0 (2018-09-25) - -* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b]) -* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537]) -* Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622]) -* Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8]) -* Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8]) -* Fix bulk and multi-bulk length truncation (Justin Brewer [109197]) -* Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94]) -* Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6]) -* Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1]) -* Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b]) -* Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96]) -* Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234]) -* Don't send negative values to `__redisAsyncCommand` (Frederik Deweerdt [706129]) -* Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c]) -* Fix libevent leak (zfz [515228]) -* Clean up GCC warning (Ichito Nagata [2ec774]) -* Keep track of errno in `__redisSetErrorFromErrno()` as snprintf may use it (Jin Qing [25cd88]) -* Solaris compilation fix (Donald Whyte [41b07d]) -* Reorder linker arguments when building examples (Tustfarm-heart [06eedd]) -* Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999]) -* libuv use after free fix (Paul Scott [cbb956]) -* Properly close socket fd on reconnect attempt (WSL [64d1ec]) -* Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78]) -* Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5]) -* Update libevent (Chris Xin [386802]) -* Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e]) -* Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6]) -* Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3]) -* Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb]) -* Compatibility fix for strerror_r (Tom Lee [bb1747]) -* Properly detect integer parse/overflow errors (Justin Brewer [93421f]) -* Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40]) -* Catch a buffer overflow when formatting the error message -* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13 -* Fix warnings, when compiled with -Wshadow -* Make hiredis compile in Cygwin on Windows, now CI-tested - -**BREAKING CHANGES**: - -* Remove backwards compatibility macro's - -This removes the following old function aliases, use the new name now: - -| Old | New | -| --------------------------- | ---------------------- | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderFree | redisReaderFree | -| redisReplyReaderFeed | redisReaderFeed | -| redisReplyReaderGetReply | redisReaderGetReply | -| redisReplyReaderSetPrivdata | redisReaderSetPrivdata | -| redisReplyReaderGetObject | redisReaderGetObject | -| redisReplyReaderGetError | redisReaderGetError | - -* The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS` - -Previously it broke some builds for people that had `DEBUG` set to some arbitrary value, -due to debugging other software. -By renaming we avoid unintentional name clashes. - -Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again. - -### 0.13.3 (2015-09-16) - -* Revert "Clear `REDIS_CONNECTED` flag when connection is closed". -* Make tests pass on FreeBSD (Thanks, Giacomo Olgeni) - - -If the `REDIS_CONNECTED` flag is cleared, -the async onDisconnect callback function will never be called. -This causes problems as the disconnect is never reported back to the user. - -### 0.13.2 (2015-08-25) - -* Prevent crash on pending replies in async code (Thanks, @switch-st) -* Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs) -* Add MacOS X addapter (Thanks, @dizzus) -* Add Qt adapter (Thanks, Pietro Cerutti) -* Add Ivykis adapter (Thanks, Gergely Nagy) - -All adapters are provided as is and are only tested where possible. - -### 0.13.1 (2015-05-03) - -This is a bug fix release. -The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code. -Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects. -Other non-C99 code can now use hiredis as usual again. -Sorry for the inconvenience. - -* Fix memory leak in async reply handling (Salvatore Sanfilippo) -* Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa) - -### 0.13.0 (2015-04-16) - -This release adds a minimal Windows compatibility layer. -The parser, standalone since v0.12.0, can now be compiled on Windows -(and thus used in other client libraries as well) - -* Windows compatibility layer for parser code (tzickel) -* Properly escape data printed to PKGCONF file (Dan Skorupski) -* Fix tests when assert() undefined (Keith Bennett, Matt Stancliff) -* Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra) - -### 0.12.1 (2015-01-26) - -* Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location -* Fix `make test` as 32 bit build on 64 bit platform - -### 0.12.0 (2015-01-22) - -* Add optional KeepAlive support - -* Try again on EINTR errors - -* Add libuv adapter - -* Add IPv6 support - -* Remove possibility of multiple close on same fd - -* Add ability to bind source address on connect - -* Add redisConnectFd() and redisFreeKeepFd() - -* Fix getaddrinfo() memory leak - -* Free string if it is unused (fixes memory leak) - -* Improve redisAppendCommandArgv performance 2.5x - -* Add support for SO_REUSEADDR - -* Fix redisvFormatCommand format parsing - -* Add GLib 2.0 adapter - -* Refactor reading code into read.c - -* Fix errno error buffers to not clobber errors - -* Generate pkgconf during build - -* Silence _BSD_SOURCE warnings - -* Improve digit counting for multibulk creation - - -### 0.11.0 - -* Increase the maximum multi-bulk reply depth to 7. - -* Increase the read buffer size from 2k to 16k. - -* Use poll(2) instead of select(2) to support large fds (>= 1024). - -### 0.10.1 - -* Makefile overhaul. Important to check out if you override one or more - variables using environment variables or via arguments to the "make" tool. - -* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements - being created by the default reply object functions. - -* Issue #43: Don't crash in an asynchronous context when Redis returns an error - reply after the connection has been made (this happens when the maximum - number of connections is reached). - -### 0.10.0 - -* See commit log. - diff --git a/ext/hiredis-0.14.1/COPYING b/ext/hiredis-0.14.1/COPYING deleted file mode 100644 index a5fc9739..00000000 --- a/ext/hiredis-0.14.1/COPYING +++ /dev/null @@ -1,29 +0,0 @@ -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-0.14.1/Makefile b/ext/hiredis-0.14.1/Makefile deleted file mode 100644 index d1f005af..00000000 --- a/ext/hiredis-0.14.1/Makefile +++ /dev/null @@ -1,214 +0,0 @@ -# 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 alloc.o -EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib -TESTS=hiredis-test -LIBNAME=libhiredis -PKGCONFNAME=hiredis.pc - -HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}') -HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}') -HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}') -HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}') - -# Installation related variables and target -PREFIX?=/usr/local -INCLUDE_PATH?=include/hiredis -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') -CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++') -OPTIMIZATION?=-O3 -WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -DEBUG_FLAGS?= -g -ggdb -REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) -REAL_LDFLAGS=$(LDFLAGS) - -DYLIBSUFFIX=so -STLIBSUFFIX=a -DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) -DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_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) -endif -ifeq ($(uname_S),Darwin) - DYLIBSUFFIX=dylib - DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX) - DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) -endif - -all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) - -# Deps (use make dep to generate this) -alloc.o: alloc.c fmacros.h alloc.h -async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h -dict.o: dict.c fmacros.h alloc.h dict.h -hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h -read.o: read.c fmacros.h read.h sds.h -sds.o: sds.c sds.h sdsalloc.h -test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.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) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) - -hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -livykis $(STLIBNAME) - -hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -framework CoreFoundation $(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 -lrt $(STLIBNAME) -endif - -ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),) -hiredis-example-qt: - @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR" - @false -else -hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) - $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ - $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore - $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ - $(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore - $(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore -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 - -INSTALL?= cp -pPR - -$(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_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_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_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH) - $(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters - $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_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 32bit-vars gprof gcov noopt diff --git a/ext/hiredis-0.14.1/README.md b/ext/hiredis-0.14.1/README.md deleted file mode 100644 index 50e2e6be..00000000 --- a/ext/hiredis-0.14.1/README.md +++ /dev/null @@ -1,410 +0,0 @@ -[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis) - -**This Readme reflects the latest changed in the master branch. See [v0.14.1](https://github.com/redis/hiredis/tree/v0.14.1) for the Readme and documentation for the latest release.** - -# HIREDIS - -Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database. - -It is minimalistic because it just adds minimal support for the protocol, but -at the same time it uses a high level printf-alike API in order to make it -much higher level than otherwise suggested by its minimal code base and the -lack of explicit bindings for every Redis command. - -Apart from supporting sending commands and receiving replies, it comes with -a reply parser that is decoupled from the I/O layer. It -is a stream parser designed for easy reusability, which can for instance be used -in higher level language bindings for efficient reply parsing. - -Hiredis only supports the binary-safe Redis protocol, so you can use it with any -Redis version >= 1.2.0. - -The library comes with multiple APIs. There is the -*synchronous API*, the *asynchronous API* and the *reply parsing API*. - -## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x - -Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now -protocol errors. This is consistent with the RESP specification. On 32-bit -platforms, the upper bound is lowered to `SIZE_MAX`. - -Change `redisReply.len` to `size_t`, as it denotes the the size of a string - -User code should compare this to `size_t` values as well. If it was used to -compare to other values, casting might be necessary or can be removed, if -casting was applied before. - -For a detailed list of changes please view our [Changelog](CHANGELOG.md). - -## Synchronous API - -To consume the synchronous API, there are only a few function calls that need to be introduced: - -```c -redisContext *redisConnect(const char *ip, int port); -void *redisCommand(redisContext *c, const char *format, ...); -void freeReplyObject(void *reply); -``` - -### Connecting - -The function `redisConnect` is used to create a so-called `redisContext`. The -context is where Hiredis holds state for a connection. The `redisContext` -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. More information on errors can be found in the **Errors** section. -After trying to connect to Redis using `redisConnect` you should -check the `err` field to see if establishing the connection was successful: -```c -redisContext *c = redisConnect("127.0.0.1", 6379); -if (c == NULL || c->err) { - if (c) { - printf("Error: %s\n", c->errstr); - // handle error - } else { - printf("Can't allocate redis context\n"); - } -} -``` - -*Note: A `redisContext` is not thread-safe.* - -### Sending commands - -There are several ways to issue commands to Redis. The first that will be introduced is -`redisCommand`. This function takes a format similar to printf. In the simplest form, -it is used like this: -```c -reply = redisCommand(context, "SET foo bar"); -``` - -The specifier `%s` interpolates a string in the command, and uses `strlen` to -determine the length of the string: -```c -reply = redisCommand(context, "SET foo %s", value); -``` -When you need to pass binary safe strings in a command, the `%b` specifier can be -used. Together with a pointer to the string, it requires a `size_t` length argument -of the string: -```c -reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen); -``` -Internally, Hiredis 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 = redisCommand(context, "SET key:%s %s", myid, value); -``` - -### Using replies - -The return value of `redisCommand` holds a reply when the command was -successfully executed. When an error occurs, the return value is `NULL` and -the `err` field in the context will be set (see section on **Errors**). -Once an error is returned the context cannot be reused and you should set up -a new connection. - -The standard replies that `redisCommand` are of the type `redisReply`. The -`type` field in the `redisReply` should be used to test what kind of reply -was received: - -* **`REDIS_REPLY_STATUS`**: - * The command replied with a status reply. The status string can be accessed using `reply->str`. - The length of this string can be accessed using `reply->len`. - -* **`REDIS_REPLY_ERROR`**: - * The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`. - -* **`REDIS_REPLY_INTEGER`**: - * The command replied with an integer. The integer value can be accessed using the - `reply->integer` field of type `long long`. - -* **`REDIS_REPLY_NIL`**: - * The command replied with a **nil** object. There is no data to access. - -* **`REDIS_REPLY_STRING`**: - * A bulk (string) reply. The value of the reply can be accessed using `reply->str`. - The length of this string can be accessed using `reply->len`. - -* **`REDIS_REPLY_ARRAY`**: - * A multi bulk reply. The number of elements in the multi bulk reply is stored in - `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well - and can be accessed via `reply->element[..index..]`. - Redis may reply with nested arrays but this is fully supported. - -Replies should be freed using the `freeReplyObject()` function. -Note that this function will take care of freeing sub-reply objects -contained in arrays and nested arrays, so there is no need for the user to -free the sub replies (it is actually harmful and will corrupt the memory). - -**Important:** the current version of hiredis (0.10.0) frees replies when the -asynchronous API is used. This means you should not call `freeReplyObject` when -you use this API. The reply is cleaned up by hiredis _after_ the callback -returns. This behavior will probably change in future releases, so make sure to -keep an eye on the changelog when upgrading (see issue #39). - -### Cleaning up - -To disconnect and free the context the following function can be used: -```c -void redisFree(redisContext *c); -``` -This function immediately closes the socket and then frees the allocations done in -creating the context. - -### Sending commands (cont'd) - -Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands. -It has the following prototype: -```c -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); -``` -It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the -arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will -use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments -need to be binary safe, the entire array of lengths `argvlen` should be provided. - -The return value has the same semantic as `redisCommand`. - -### Pipelining - -To explain how Hiredis supports pipelining in a blocking connection, there needs to be -understanding of the internal execution flow. - -When any of the functions in the `redisCommand` family is called, Hiredis first formats the -command according to the Redis protocol. The formatted command is then put in the output buffer -of the context. This output buffer is dynamic, so it can hold any number of commands. -After the command is put in the output buffer, `redisGetReply` is called. This function has the -following two execution paths: - -1. The input buffer is non-empty: - * Try to parse a single reply from the input buffer and return it - * If no reply could be parsed, continue at *2* -2. The input buffer is empty: - * Write the **entire** output buffer to the socket - * Read from the socket until a single reply could be parsed - -The function `redisGetReply` 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 `redisCommand` family, apart from not returning a reply: -```c -void redisAppendCommand(redisContext *c, const char *format, ...); -void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); -``` -After calling either function one or more times, `redisGetReply` 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. - -The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and -a single call to `read(2)`): -```c -redisReply *reply; -redisAppendCommand(context,"SET foo bar"); -redisAppendCommand(context,"GET foo"); -redisGetReply(context,&reply); // reply for SET -freeReplyObject(reply); -redisGetReply(context,&reply); // reply for GET -freeReplyObject(reply); -``` -This API can also be used to implement a blocking subscriber: -```c -reply = redisCommand(context,"SUBSCRIBE foo"); -freeReplyObject(reply); -while(redisGetReply(context,&reply) == REDIS_OK) { - // consume message - freeReplyObject(reply); -} -``` -### Errors - -When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is -returned. The `err` field inside the context will be non-zero and set to one of the -following constants: - -* **`REDIS_ERR_IO`**: - There was an I/O error while creating the connection, trying to write - to the socket or read from the socket. If you included `errno.h` in your - application, you can use the global `errno` variable to find out what is - wrong. - -* **`REDIS_ERR_EOF`**: - The server closed the connection which resulted in an empty read. - -* **`REDIS_ERR_PROTOCOL`**: - There was an error while parsing the protocol. - -* **`REDIS_ERR_OTHER`**: - Any other error. Currently, it is only used when a specified hostname to connect - to cannot be resolved. - -In every case, the `errstr` field in the context will be set to hold a string representation -of the error. - -## Asynchronous API - -Hiredis comes with an asynchronous API that works easily with any event library. -Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html) -and [libevent](http://monkey.org/~provos/libevent/). - -### 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. - -*Note: A `redisAsyncContext` is not thread-safe.* - -```c -redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); -if (c->err) { - printf("Error: %s\n", c->errstr); - // handle error -} -``` - -The 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. - -The context object is always freed after the disconnect callback fired. When a reconnect is needed, -the disconnect callback is a good point to do so. - -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 redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); -``` -### Sending commands and their callbacks - -In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. -Therefore, unlike the synchronous API, there is only a single way to send commands. -Because commands are sent to Redis 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(redisAsyncContext *c, 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 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); -``` -Both functions 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 `redisAsyncCommand` 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 asynchronous connection can be terminated using: -```c -void redisAsyncDisconnect(redisAsyncContext *ac); -``` -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 context object after it is created. -See the `adapters/` directory for bindings to *libev* and *libevent*. - -## Reply parsing API - -Hiredis comes with a reply parsing API that makes it easy for writing higher -level language bindings. - -The reply parsing API consists of the following functions: -```c -redisReader *redisReaderCreate(void); -void redisReaderFree(redisReader *reader); -int redisReaderFeed(redisReader *reader, const char *buf, size_t len); -int redisReaderGetReply(redisReader *reader, void **reply); -``` -The same set of functions are used internally by hiredis when creating a -normal Redis context, the above API just exposes it to the user for a direct -usage. - -### Usage - -The function `redisReaderCreate` creates a `redisReader` structure that holds a -buffer with unparsed data and state for the protocol parser. - -Incoming data -- most likely from a socket -- can be placed in the internal -buffer of the `redisReader` using `redisReaderFeed`. This function will make a -copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed -when `redisReaderGetReply` is called. This function returns an integer status -and a reply object (as described above) via `void **reply`. The returned status -can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went -wrong (either a protocol error, or an out of memory error). - -The parser limits the level of nesting for multi bulk payloads to 7. If the -multi bulk nesting level is higher than this, the parser returns an error. - -### Customizing replies - -The function `redisReaderGetReply` creates `redisReply` and makes the function -argument `reply` point to the created `redisReply` variable. For instance, if -the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply` -will hold the status as a vanilla C string. However, the functions that are -responsible for creating instances of the `redisReply` can be customized by -setting the `fn` field on the `redisReader` struct. This should be done -immediately after creating the `redisReader`. - -For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c) -uses customized reply object functions to create Ruby objects. - -### Reader max buffer - -Both when using the Reader API directly or when using it indirectly via a -normal Redis context, the redisReader structure uses a buffer in order to -accumulate data from the server. -Usually this buffer is destroyed when it is empty and is larger than 16 -KiB in order to avoid wasting memory in unused buffers - -However when working with very big payloads destroying the buffer may slow -down performances considerably, so it is possible to modify the max size of -an idle buffer changing the value of the `maxbuf` field of the reader structure -to the desired value. The special value of 0 means that there is no maximum -value for an idle buffer, so the buffer will never get freed. - -For instance if you have a normal Redis context you can set the maximum idle -buffer to zero (unlimited) just with: -```c -context->reader->maxbuf = 0; -``` -This should be done only in order to maximize performances when working with -large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again -as soon as possible in order to prevent allocation of useless memory. - -## AUTHORS - -Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and -Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license. -Hiredis is currently maintained by Matt Stancliff (matt at genges dot com) and -Jan-Erik Rediger (janerik at fnordig dot com) diff --git a/ext/hiredis-0.14.1/adapters/ae.h b/ext/hiredis-0.14.1/adapters/ae.h deleted file mode 100644 index 03939928..00000000 --- a/ext/hiredis-0.14.1/adapters/ae.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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" - -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*)hi_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; -} -#endif diff --git a/ext/hiredis-0.14.1/adapters/glib.h b/ext/hiredis-0.14.1/adapters/glib.h deleted file mode 100644 index e0a6411d..00000000 --- a/ext/hiredis-0.14.1/adapters/glib.h +++ /dev/null @@ -1,153 +0,0 @@ -#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 = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_IN; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_del_read (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_IN; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_add_write (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_OUT; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_del_write (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_OUT; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_cleanup (gpointer data) -{ - RedisSource *source = (RedisSource *)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((GSource *)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-0.14.1/adapters/ivykis.h b/ext/hiredis-0.14.1/adapters/ivykis.h deleted file mode 100644 index 75616ee2..00000000 --- a/ext/hiredis-0.14.1/adapters/ivykis.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef __HIREDIS_IVYKIS_H__ -#define __HIREDIS_IVYKIS_H__ -#include -#include "../hiredis.h" -#include "../async.h" - -typedef struct redisIvykisEvents { - redisAsyncContext *context; - struct iv_fd fd; -} redisIvykisEvents; - -static void redisIvykisReadEvent(void *arg) { - redisAsyncContext *context = (redisAsyncContext *)arg; - redisAsyncHandleRead(context); -} - -static void redisIvykisWriteEvent(void *arg) { - redisAsyncContext *context = (redisAsyncContext *)arg; - redisAsyncHandleWrite(context); -} - -static void redisIvykisAddRead(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent); -} - -static void redisIvykisDelRead(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_in(&e->fd, NULL); -} - -static void redisIvykisAddWrite(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent); -} - -static void redisIvykisDelWrite(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_out(&e->fd, NULL); -} - -static void redisIvykisCleanup(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - - iv_fd_unregister(&e->fd); - free(e); -} - -static int redisIvykisAttach(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisIvykisEvents *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 = (redisIvykisEvents*)hi_malloc(sizeof(*e)); - e->context = ac; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisIvykisAddRead; - ac->ev.delRead = redisIvykisDelRead; - ac->ev.addWrite = redisIvykisAddWrite; - ac->ev.delWrite = redisIvykisDelWrite; - ac->ev.cleanup = redisIvykisCleanup; - ac->ev.data = e; - - /* Initialize and install read/write events */ - IV_FD_INIT(&e->fd); - e->fd.fd = c->fd; - e->fd.handler_in = redisIvykisReadEvent; - e->fd.handler_out = redisIvykisWriteEvent; - e->fd.handler_err = NULL; - e->fd.cookie = e->context; - - iv_fd_register(&e->fd); - - return REDIS_OK; -} -#endif diff --git a/ext/hiredis-0.14.1/adapters/libev.h b/ext/hiredis-0.14.1/adapters/libev.h deleted file mode 100644 index abad4363..00000000 --- a/ext/hiredis-0.14.1/adapters/libev.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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*)hi_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-0.14.1/adapters/libevent.h b/ext/hiredis-0.14.1/adapters/libevent.h deleted file mode 100644 index f2330d6f..00000000 --- a/ext/hiredis-0.14.1/adapters/libevent.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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" - -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_free(e->rev); - event_free(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*)hi_calloc(1, 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 */ - e->rev = event_new(base, c->fd, EV_READ, redisLibeventReadEvent, e); - e->wev = event_new(base, c->fd, EV_WRITE, redisLibeventWriteEvent, e); - event_add(e->rev, NULL); - event_add(e->wev, NULL); - return REDIS_OK; -} -#endif diff --git a/ext/hiredis-0.14.1/adapters/libuv.h b/ext/hiredis-0.14.1/adapters/libuv.h deleted file mode 100644 index ff08c25e..00000000 --- a/ext/hiredis-0.14.1/adapters/libuv.h +++ /dev/null @@ -1,122 +0,0 @@ -#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 (p->context != NULL && (events & UV_READABLE)) { - redisAsyncHandleRead(p->context); - } - if (p->context != NULL && (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; - - p->context = NULL; // indicate that context might no longer exist - 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-0.14.1/adapters/macosx.h b/ext/hiredis-0.14.1/adapters/macosx.h deleted file mode 100644 index 72121f60..00000000 --- a/ext/hiredis-0.14.1/adapters/macosx.h +++ /dev/null @@ -1,114 +0,0 @@ -// -// Created by Дмитрий Бахвалов on 13.07.15. -// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. -// - -#ifndef __HIREDIS_MACOSX_H__ -#define __HIREDIS_MACOSX_H__ - -#include - -#include "../hiredis.h" -#include "../async.h" - -typedef struct { - redisAsyncContext *context; - CFSocketRef socketRef; - CFRunLoopSourceRef sourceRef; -} RedisRunLoop; - -static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { - if( redisRunLoop != NULL ) { - if( redisRunLoop->sourceRef != NULL ) { - CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); - CFRelease(redisRunLoop->sourceRef); - } - if( redisRunLoop->socketRef != NULL ) { - CFSocketInvalidate(redisRunLoop->socketRef); - CFRelease(redisRunLoop->socketRef); - } - free(redisRunLoop); - } - return REDIS_ERR; -} - -static void redisMacOSAddRead(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); -} - -static void redisMacOSDelRead(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); -} - -static void redisMacOSAddWrite(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); -} - -static void redisMacOSDelWrite(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); -} - -static void redisMacOSCleanup(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - freeRedisRunLoop(redisRunLoop); -} - -static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { - redisAsyncContext* context = (redisAsyncContext*) info; - - switch (callbackType) { - case kCFSocketReadCallBack: - redisAsyncHandleRead(context); - break; - - case kCFSocketWriteCallBack: - redisAsyncHandleWrite(context); - break; - - default: - break; - } -} - -static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { - redisContext *redisCtx = &(redisAsyncCtx->c); - - /* Nothing should be attached when something is already attached */ - if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; - - RedisRunLoop* redisRunLoop = (RedisRunLoop*) calloc(1, sizeof(RedisRunLoop)); - if( !redisRunLoop ) return REDIS_ERR; - - /* Setup redis stuff */ - redisRunLoop->context = redisAsyncCtx; - - redisAsyncCtx->ev.addRead = redisMacOSAddRead; - redisAsyncCtx->ev.delRead = redisMacOSDelRead; - redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; - redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; - redisAsyncCtx->ev.cleanup = redisMacOSCleanup; - redisAsyncCtx->ev.data = redisRunLoop; - - /* Initialize and install read/write events */ - CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; - - redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, - kCFSocketReadCallBack | kCFSocketWriteCallBack, - redisMacOSAsyncCallback, - &socketCtx); - if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); - - redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); - if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); - - CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); - - return REDIS_OK; -} - -#endif - diff --git a/ext/hiredis-0.14.1/adapters/qt.h b/ext/hiredis-0.14.1/adapters/qt.h deleted file mode 100644 index 5cc02e6c..00000000 --- a/ext/hiredis-0.14.1/adapters/qt.h +++ /dev/null @@ -1,135 +0,0 @@ -/*- - * Copyright (C) 2014 Pietro Cerutti - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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_QT_H__ -#define __HIREDIS_QT_H__ -#include -#include "../async.h" - -static void RedisQtAddRead(void *); -static void RedisQtDelRead(void *); -static void RedisQtAddWrite(void *); -static void RedisQtDelWrite(void *); -static void RedisQtCleanup(void *); - -class RedisQtAdapter : public QObject { - - Q_OBJECT - - friend - void RedisQtAddRead(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->addRead(); - } - - friend - void RedisQtDelRead(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->delRead(); - } - - friend - void RedisQtAddWrite(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->addWrite(); - } - - friend - void RedisQtDelWrite(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->delWrite(); - } - - friend - void RedisQtCleanup(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->cleanup(); - } - - public: - RedisQtAdapter(QObject * parent = 0) - : QObject(parent), m_ctx(0), m_read(0), m_write(0) { } - - ~RedisQtAdapter() { - if (m_ctx != 0) { - m_ctx->ev.data = NULL; - } - } - - int setContext(redisAsyncContext * ac) { - if (ac->ev.data != NULL) { - return REDIS_ERR; - } - m_ctx = ac; - m_ctx->ev.data = this; - m_ctx->ev.addRead = RedisQtAddRead; - m_ctx->ev.delRead = RedisQtDelRead; - m_ctx->ev.addWrite = RedisQtAddWrite; - m_ctx->ev.delWrite = RedisQtDelWrite; - m_ctx->ev.cleanup = RedisQtCleanup; - return REDIS_OK; - } - - private: - void addRead() { - if (m_read) return; - m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0); - connect(m_read, SIGNAL(activated(int)), this, SLOT(read())); - } - - void delRead() { - if (!m_read) return; - delete m_read; - m_read = 0; - } - - void addWrite() { - if (m_write) return; - m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0); - connect(m_write, SIGNAL(activated(int)), this, SLOT(write())); - } - - void delWrite() { - if (!m_write) return; - delete m_write; - m_write = 0; - } - - void cleanup() { - delRead(); - delWrite(); - } - - private slots: - void read() { redisAsyncHandleRead(m_ctx); } - void write() { redisAsyncHandleWrite(m_ctx); } - - private: - redisAsyncContext * m_ctx; - QSocketNotifier * m_read; - QSocketNotifier * m_write; -}; - -#endif /* !__HIREDIS_QT_H__ */ diff --git a/ext/hiredis-0.14.1/alloc.c b/ext/hiredis-0.14.1/alloc.c deleted file mode 100644 index 55c3020e..00000000 --- a/ext/hiredis-0.14.1/alloc.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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 "alloc.h" -#include - -void *hi_malloc(size_t size) { - void *ptr = malloc(size); - if (ptr == NULL) - HIREDIS_OOM_HANDLER; - - return ptr; -} - -void *hi_calloc(size_t nmemb, size_t size) { - void *ptr = calloc(nmemb, size); - if (ptr == NULL) - HIREDIS_OOM_HANDLER; - - return ptr; -} - -void *hi_realloc(void *ptr, size_t size) { - void *newptr = realloc(ptr, size); - if (newptr == NULL) - HIREDIS_OOM_HANDLER; - - return newptr; -} - -char *hi_strdup(const char *str) { - char *newstr = strdup(str); - if (newstr == NULL) - HIREDIS_OOM_HANDLER; - - return newstr; -} diff --git a/ext/hiredis-0.14.1/alloc.h b/ext/hiredis-0.14.1/alloc.h deleted file mode 100644 index 2c9b04e3..00000000 --- a/ext/hiredis-0.14.1/alloc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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_ALLOC_H -#define HIREDIS_ALLOC_H - -#include /* for size_t */ - -#ifndef HIREDIS_OOM_HANDLER -#define HIREDIS_OOM_HANDLER abort() -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void *hi_malloc(size_t size); -void *hi_calloc(size_t nmemb, size_t size); -void *hi_realloc(void *ptr, size_t size); -char *hi_strdup(const char *str); - -#ifdef __cplusplus -} -#endif - -#endif /* HIREDIS_ALLOC_H */ diff --git a/ext/hiredis-0.14.1/appveyor.yml b/ext/hiredis-0.14.1/appveyor.yml deleted file mode 100644 index 819efbd5..00000000 --- a/ext/hiredis-0.14.1/appveyor.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) -environment: - matrix: - - CYG_BASH: C:\cygwin64\bin\bash - CC: gcc - - CYG_BASH: C:\cygwin\bin\bash - CC: gcc - TARGET: 32bit - TARGET_VARS: 32bit-vars - -clone_depth: 1 - -# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail -init: - - git config --global core.autocrlf input - -# Install needed build dependencies -install: - - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - -build_script: - - 'echo building...' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 - * 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 "alloc.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 = hi_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->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); - } - } - - /* 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. */ - int ret = __redisShiftCallback(&ac->replies,NULL); - assert(ret == 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; - redisCallback *cb; - 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) { - cb = dictGetEntryVal(de); - - /* If this is an subscribe reply decrease pending counter. */ - if (strcasecmp(stype+pvariant,"subscribe") == 0) { - cb->pending_subs -= 1; - } - - memcpy(dstcb,cb,sizeof(*dstcb)); - - /* If this is an unsubscribe message, remove it. */ - if (strcasecmp(stype+pvariant,"unsubscribe") == 0) { - if (cb->pending_subs == 0) - dictDelete(callbacks,sname); - - /* If this was the last unsubscribe message, revert to - * non-subscribe mode. */ - assert(reply->element[2]->type == REDIS_REPLY_INTEGER); - - /* Unset subscribed flag only when no pipelined pending subscribe. */ - if (reply->element[2]->integer == 0 - && dictSize(ac->sub.channels) == 0 - && dictSize(ac->sub.patterns) == 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, 0, 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 - && ac->replies.head == NULL) { - __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 successful, 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; - struct dict *cbdict; - dictEntry *de; - redisCallback *existcb; - 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; - cb.pending_subs = 1; - - /* 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) - cbdict = ac->sub.patterns; - else - cbdict = ac->sub.channels; - - de = dictFind(cbdict,sname); - - if (de != NULL) { - existcb = dictGetEntryVal(de); - cb.pending_subs = existcb->pending_subs + 1; - } - - ret = dictReplace(cbdict,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); - if (len < 0) - return REDIS_ERR; - 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-0.14.1/async.h b/ext/hiredis-0.14.1/async.h deleted file mode 100644 index e69d8409..00000000 --- a/ext/hiredis-0.14.1/async.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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; - int pending_subs; - 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; - - /* 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-0.14.1/dict.c b/ext/hiredis-0.14.1/dict.c deleted file mode 100644 index 29cdc190..00000000 --- a/ext/hiredis-0.14.1/dict.c +++ /dev/null @@ -1,339 +0,0 @@ -/* 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 "alloc.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 = hi_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 = hi_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 succeed. */ - 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 = hi_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 initial 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-0.14.1/dict.h b/ext/hiredis-0.14.1/dict.h deleted file mode 100644 index 95fcd280..00000000 --- a/ext/hiredis-0.14.1/dict.h +++ /dev/null @@ -1,126 +0,0 @@ -/* 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-0.14.1/examples/example-ae.c b/ext/hiredis-0.14.1/examples/example-ae.c deleted file mode 100644 index 8efa7306..00000000 --- a/ext/hiredis-0.14.1/examples/example-ae.c +++ /dev/null @@ -1,62 +0,0 @@ -#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-0.14.1/examples/example-glib.c b/ext/hiredis-0.14.1/examples/example-glib.c deleted file mode 100644 index d6e10f8e..00000000 --- a/ext/hiredis-0.14.1/examples/example-glib.c +++ /dev/null @@ -1,73 +0,0 @@ -#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-0.14.1/examples/example-ivykis.c b/ext/hiredis-0.14.1/examples/example-ivykis.c deleted file mode 100644 index 67affcef..00000000 --- a/ext/hiredis-0.14.1/examples/example-ivykis.c +++ /dev/null @@ -1,58 +0,0 @@ -#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); - - iv_init(); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisIvykisAttach(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"); - - iv_main(); - - iv_deinit(); - - return 0; -} diff --git a/ext/hiredis-0.14.1/examples/example-libev.c b/ext/hiredis-0.14.1/examples/example-libev.c deleted file mode 100644 index cc8b166e..00000000 --- a/ext/hiredis-0.14.1/examples/example-libev.c +++ /dev/null @@ -1,52 +0,0 @@ -#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-0.14.1/examples/example-libevent.c b/ext/hiredis-0.14.1/examples/example-libevent.c deleted file mode 100644 index d333c22b..00000000 --- a/ext/hiredis-0.14.1/examples/example-libevent.c +++ /dev/null @@ -1,53 +0,0 @@ -#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-0.14.1/examples/example-libuv.c b/ext/hiredis-0.14.1/examples/example-libuv.c deleted file mode 100644 index a5462d41..00000000 --- a/ext/hiredis-0.14.1/examples/example-libuv.c +++ /dev/null @@ -1,53 +0,0 @@ -#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-0.14.1/examples/example-macosx.c b/ext/hiredis-0.14.1/examples/example-macosx.c deleted file mode 100644 index bc84ed5b..00000000 --- a/ext/hiredis-0.14.1/examples/example-macosx.c +++ /dev/null @@ -1,66 +0,0 @@ -// -// Created by Дмитрий Бахвалов on 13.07.15. -// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. -// - -#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; - } - CFRunLoopStop(CFRunLoopGetCurrent()); - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - CFRunLoopRef loop = CFRunLoopGetCurrent(); - if( !loop ) { - printf("Error: Cannot get current run loop\n"); - return 1; - } - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisMacOSAttach(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"); - - CFRunLoopRun(); - - return 0; -} - diff --git a/ext/hiredis-0.14.1/examples/example-qt.cpp b/ext/hiredis-0.14.1/examples/example-qt.cpp deleted file mode 100644 index f524c3f3..00000000 --- a/ext/hiredis-0.14.1/examples/example-qt.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -using namespace std; - -#include -#include - -#include "example-qt.h" - -void getCallback(redisAsyncContext *, void * r, void * privdata) { - - redisReply * reply = static_cast(r); - ExampleQt * ex = static_cast(privdata); - if (reply == nullptr || ex == nullptr) return; - - cout << "key: " << reply->str << endl; - - ex->finish(); -} - -void ExampleQt::run() { - - m_ctx = redisAsyncConnect("localhost", 6379); - - if (m_ctx->err) { - cerr << "Error: " << m_ctx->errstr << endl; - redisAsyncFree(m_ctx); - emit finished(); - } - - m_adapter.setContext(m_ctx); - - redisAsyncCommand(m_ctx, NULL, NULL, "SET key %s", m_value); - redisAsyncCommand(m_ctx, getCallback, this, "GET key"); -} - -int main (int argc, char **argv) { - - QCoreApplication app(argc, argv); - - ExampleQt example(argv[argc-1]); - - QObject::connect(&example, SIGNAL(finished()), &app, SLOT(quit())); - QTimer::singleShot(0, &example, SLOT(run())); - - return app.exec(); -} diff --git a/ext/hiredis-0.14.1/examples/example-qt.h b/ext/hiredis-0.14.1/examples/example-qt.h deleted file mode 100644 index 374f4766..00000000 --- a/ext/hiredis-0.14.1/examples/example-qt.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __HIREDIS_EXAMPLE_QT_H -#define __HIREDIS_EXAMPLE_QT_H - -#include - -class ExampleQt : public QObject { - - Q_OBJECT - - public: - ExampleQt(const char * value, QObject * parent = 0) - : QObject(parent), m_value(value) {} - - signals: - void finished(); - - public slots: - void run(); - - private: - void finish() { emit finished(); } - - private: - const char * m_value; - redisAsyncContext * m_ctx; - RedisQtAdapter m_adapter; - - friend - void getCallback(redisAsyncContext *, void *, void *); -}; - -#endif /* !__HIREDIS_EXAMPLE_QT_H */ diff --git a/ext/hiredis-0.14.1/examples/example.c b/ext/hiredis-0.14.1/examples/example.c deleted file mode 100644 index 4d494c55..00000000 --- a/ext/hiredis-0.14.1/examples/example.c +++ /dev/null @@ -1,78 +0,0 @@ -#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,"%u",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-0.14.1/fmacros.h b/ext/hiredis-0.14.1/fmacros.h deleted file mode 100644 index 3227faaf..00000000 --- a/ext/hiredis-0.14.1/fmacros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __HIREDIS_FMACRO_H -#define __HIREDIS_FMACRO_H - -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L - -#if defined(__APPLE__) && defined(__MACH__) -/* Enable TCP_KEEPALIVE */ -#define _DARWIN_C_SOURCE -#endif - -#endif diff --git a/ext/hiredis-0.14.1/hiredis.c b/ext/hiredis-0.14.1/hiredis.c deleted file mode 100644 index 98f43c99..00000000 --- a/ext/hiredis-0.14.1/hiredis.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * 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++) - freeReplyObject(r->element[j]); - free(r->element); - } - break; - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_STRING: - 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); - 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, "$%u\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); - 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->obuf = sdsempty(); - c->reader = redisReaderCreate(); - - 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); - sdsfree(c->obuf); - redisReaderFree(c->reader); - free(c->tcp.host); - free(c->tcp.source_addr); - free(c->unix_sock.path); - 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(); - if (c == NULL) - return NULL; - 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(); - if (c == NULL) - return NULL; - 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 - * successfully 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 occurred 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 successfully 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; - va_start(ap,format); - void *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-0.14.1/hiredis.h b/ext/hiredis-0.14.1/hiredis.h deleted file mode 100644 index d945bf20..00000000 --- a/ext/hiredis-0.14.1/hiredis.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 */ -#include "alloc.h" /* for allocation wrappers */ - -#define HIREDIS_MAJOR 0 -#define HIREDIS_MINOR 14 -#define HIREDIS_PATCH 1 -#define HIREDIS_SONAME 0.14 - -/* 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 - -#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 */ - size_t 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 successful 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-0.14.1/include/hiredis/alloc.h b/ext/hiredis-0.14.1/include/hiredis/alloc.h deleted file mode 100644 index 2c9b04e3..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/alloc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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_ALLOC_H -#define HIREDIS_ALLOC_H - -#include /* for size_t */ - -#ifndef HIREDIS_OOM_HANDLER -#define HIREDIS_OOM_HANDLER abort() -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void *hi_malloc(size_t size); -void *hi_calloc(size_t nmemb, size_t size); -void *hi_realloc(void *ptr, size_t size); -char *hi_strdup(const char *str); - -#ifdef __cplusplus -} -#endif - -#endif /* HIREDIS_ALLOC_H */ diff --git a/ext/hiredis-0.14.1/include/hiredis/async.h b/ext/hiredis-0.14.1/include/hiredis/async.h deleted file mode 100644 index e69d8409..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/async.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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; - int pending_subs; - 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; - - /* 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-0.14.1/include/hiredis/dict.h b/ext/hiredis-0.14.1/include/hiredis/dict.h deleted file mode 100644 index 95fcd280..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/dict.h +++ /dev/null @@ -1,126 +0,0 @@ -/* 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-0.14.1/include/hiredis/fmacros.h b/ext/hiredis-0.14.1/include/hiredis/fmacros.h deleted file mode 100644 index 3227faaf..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/fmacros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __HIREDIS_FMACRO_H -#define __HIREDIS_FMACRO_H - -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L - -#if defined(__APPLE__) && defined(__MACH__) -/* Enable TCP_KEEPALIVE */ -#define _DARWIN_C_SOURCE -#endif - -#endif diff --git a/ext/hiredis-0.14.1/include/hiredis/hiredis.h b/ext/hiredis-0.14.1/include/hiredis/hiredis.h deleted file mode 100644 index d945bf20..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/hiredis.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 */ -#include "alloc.h" /* for allocation wrappers */ - -#define HIREDIS_MAJOR 0 -#define HIREDIS_MINOR 14 -#define HIREDIS_PATCH 1 -#define HIREDIS_SONAME 0.14 - -/* 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 - -#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 */ - size_t 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 successful 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-0.14.1/include/hiredis/net.h b/ext/hiredis-0.14.1/include/hiredis/net.h deleted file mode 100644 index d9dc3625..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/net.h +++ /dev/null @@ -1,49 +0,0 @@ -/* 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" - -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-0.14.1/include/hiredis/read.h b/ext/hiredis-0.14.1/include/hiredis/read.h deleted file mode 100644 index 2988aa45..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/read.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 occurred. 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... */ - -#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. */ - -#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); - -#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/hiredis-0.14.1/include/hiredis/sds.h b/ext/hiredis-0.14.1/include/hiredis/sds.h deleted file mode 100644 index 13be75a9..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/sds.h +++ /dev/null @@ -1,273 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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 -#include - -typedef char *sds; - -/* Note: sdshdr5 is never used, we just access the flags byte directly. - * However is here to document the layout of type 5 SDS strings. */ -struct __attribute__ ((__packed__)) sdshdr5 { - unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr8 { - uint8_t len; /* used */ - uint8_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr16 { - uint16_t len; /* used */ - uint16_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr32 { - uint32_t len; /* used */ - uint32_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr64 { - uint64_t len; /* used */ - uint64_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; - -#define SDS_TYPE_5 0 -#define SDS_TYPE_8 1 -#define SDS_TYPE_16 2 -#define SDS_TYPE_32 3 -#define SDS_TYPE_64 4 -#define SDS_TYPE_MASK 7 -#define SDS_TYPE_BITS 3 -#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); -#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) -#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) - -static inline size_t sdslen(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->len; - case SDS_TYPE_16: - return SDS_HDR(16,s)->len; - case SDS_TYPE_32: - return SDS_HDR(32,s)->len; - case SDS_TYPE_64: - return SDS_HDR(64,s)->len; - } - return 0; -} - -static inline size_t sdsavail(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - return 0; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - return sh->alloc - sh->len; - } - } - return 0; -} - -static inline void sdssetlen(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len = newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len = newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len = newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len = newlen; - break; - } -} - -static inline void sdsinclen(sds s, size_t inc) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len += inc; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len += inc; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len += inc; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len += inc; - break; - } -} - -/* sdsalloc() = sdsavail() + sdslen() */ -static inline size_t sdsalloc(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->alloc; - case SDS_TYPE_16: - return SDS_HDR(16,s)->alloc; - case SDS_TYPE_32: - return SDS_HDR(32,s)->alloc; - case SDS_TYPE_64: - return SDS_HDR(64,s)->alloc; - } - return 0; -} - -static inline void sdssetalloc(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - /* Nothing to do, this type has no total allocation info. */ - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->alloc = newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->alloc = newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->alloc = newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->alloc = newlen; - break; - } -} - -sds sdsnewlen(const void *init, size_t initlen); -sds sdsnew(const char *init); -sds sdsempty(void); -sds sdsdup(const sds s); -void sdsfree(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, ...); -sds 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); -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); -void *sdsAllocPtr(sds s); - -/* Export the allocator used by SDS to the program using SDS. - * Sometimes the program SDS is linked to, may use a different set of - * allocators, but may want to allocate or free things that SDS will - * respectively free or allocate. */ -void *sds_malloc(size_t size); -void *sds_realloc(void *ptr, size_t size); -void sds_free(void *ptr); - -#ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); -#endif - -#endif diff --git a/ext/hiredis-0.14.1/include/hiredis/sdsalloc.h b/ext/hiredis-0.14.1/include/hiredis/sdsalloc.h deleted file mode 100644 index f43023c4..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/sdsalloc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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. - */ - -/* SDS allocator selection. - * - * This file is used in order to change the SDS allocator at compile time. - * Just define the following defines to what you want to use. Also add - * the include of your alternate allocator if needed (not needed in order - * to use the default libc allocator). */ - -#define s_malloc malloc -#define s_realloc realloc -#define s_free free diff --git a/ext/hiredis-0.14.1/include/hiredis/win32.h b/ext/hiredis-0.14.1/include/hiredis/win32.h deleted file mode 100644 index 1a27c18f..00000000 --- a/ext/hiredis-0.14.1/include/hiredis/win32.h +++ /dev/null @@ -1,42 +0,0 @@ -#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/hiredis-0.14.1/lib/centos8/libhiredis.a b/ext/hiredis-0.14.1/lib/centos8/libhiredis.a deleted file mode 100644 index 0b963879..00000000 Binary files a/ext/hiredis-0.14.1/lib/centos8/libhiredis.a and /dev/null differ diff --git a/ext/hiredis-0.14.1/lib/macos/libhiredis.a b/ext/hiredis-0.14.1/lib/macos/libhiredis.a deleted file mode 100644 index 02bdb880..00000000 Binary files a/ext/hiredis-0.14.1/lib/macos/libhiredis.a and /dev/null differ diff --git a/ext/hiredis-0.14.1/net.c b/ext/hiredis-0.14.1/net.c deleted file mode 100644 index d71bbcd5..00000000 --- a/ext/hiredis-0.14.1/net.c +++ /dev/null @@ -1,477 +0,0 @@ -/* 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) { - int errorno = errno; /* snprintf() may change errno */ - char buf[128] = { 0 }; - size_t len = 0; - - if (prefix != NULL) - len = snprintf(buf,sizeof(buf),"%s: ",prefix); - strerror_r(errorno, (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; - -#if defined(__APPLE__) && defined(__MACH__) - 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__) - 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 redisContextTimeoutMsec(redisContext *c, long *result) -{ - const struct timeval *timeout = c->timeout; - long msec = -1; - - /* Only use timeout when not NULL. */ - if (timeout != NULL) { - if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { - *result = msec; - return REDIS_ERR; - } - - msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000); - - if (msec < 0 || msec > INT_MAX) { - msec = INT_MAX; - } - } - - *result = msec; - return REDIS_OK; -} - -static int redisContextWaitReady(redisContext *c, long msec) { - struct pollfd wfd[1]; - - wfd[0].fd = c->fd; - wfd[0].events = POLLOUT; - - 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; - long timeout_msec = -1; - - servinfo = NULL; - 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) { - free(c->tcp.host); - - c->tcp.host = hi_strdup(addr); - } - - if (timeout) { - if (c->timeout != timeout) { - if (c->timeout == NULL) - c->timeout = hi_malloc(sizeof(struct timeval)); - - memcpy(c->timeout, timeout, sizeof(struct timeval)); - } - } else { - free(c->timeout); - c->timeout = NULL; - } - - if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) { - __redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified"); - goto error; - } - - 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 = hi_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) { - freeaddrinfo(bservinfo); - 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 { - redisContextCloseFd(c); - goto addrretry; - } - } else { - if (redisContextWaitReady(c,timeout_msec) != 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: - if(servinfo) { - 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; - long timeout_msec = -1; - - if (redisCreateSocket(c,AF_UNIX) < 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 = hi_strdup(path); - - if (timeout) { - if (c->timeout != timeout) { - if (c->timeout == NULL) - c->timeout = hi_malloc(sizeof(struct timeval)); - - memcpy(c->timeout, timeout, sizeof(struct timeval)); - } - } else { - free(c->timeout); - c->timeout = NULL; - } - - if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK) - return REDIS_ERR; - - sa.sun_family = AF_UNIX; - 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,timeout_msec) != 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-0.14.1/net.h b/ext/hiredis-0.14.1/net.h deleted file mode 100644 index d9dc3625..00000000 --- a/ext/hiredis-0.14.1/net.h +++ /dev/null @@ -1,49 +0,0 @@ -/* 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" - -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-0.14.1/read.c b/ext/hiredis-0.14.1/read.c deleted file mode 100644 index cc212677..00000000 --- a/ext/hiredis-0.14.1/read.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * 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 - -#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. */ - 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 (pos==_len) { - /* Not found. */ - return NULL; - } else { - if (s[pos+1] == '\n') { - /* Found. */ - return s+pos; - } else { - /* Continue searching. */ - pos++; - } - } - } - return NULL; -} - -/* Convert a string into a long long. Returns REDIS_OK if the string could be - * parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value - * will be set to the parsed value when appropriate. - * - * Note that this function demands that the string strictly represents - * a long long: no spaces or other characters before or after the string - * representing the number are accepted, nor zeroes at the start if not - * for the string "0" representing the zero number. - * - * Because of its strictness, it is safe to use this function to check if - * you can convert a string into a long long, and obtain back the string - * from the number without any loss in the string representation. */ -static int string2ll(const char *s, size_t slen, long long *value) { - const char *p = s; - size_t plen = 0; - int negative = 0; - unsigned long long v; - - if (plen == slen) - return REDIS_ERR; - - /* Special case: first and only digit is 0. */ - if (slen == 1 && p[0] == '0') { - if (value != NULL) *value = 0; - return REDIS_OK; - } - - if (p[0] == '-') { - negative = 1; - p++; plen++; - - /* Abort on only a negative sign. */ - if (plen == slen) - return REDIS_ERR; - } - - /* First digit should be 1-9, otherwise the string should just be 0. */ - if (p[0] >= '1' && p[0] <= '9') { - v = p[0]-'0'; - p++; plen++; - } else if (p[0] == '0' && slen == 1) { - *value = 0; - return REDIS_OK; - } else { - return REDIS_ERR; - } - - while (plen < slen && p[0] >= '0' && p[0] <= '9') { - if (v > (ULLONG_MAX / 10)) /* Overflow. */ - return REDIS_ERR; - v *= 10; - - if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */ - return REDIS_ERR; - v += p[0]-'0'; - - p++; plen++; - } - - /* Return if not all bytes were used. */ - if (plen < slen) - return REDIS_ERR; - - if (negative) { - if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */ - return REDIS_ERR; - if (value != NULL) *value = -v; - } else { - if (v > LLONG_MAX) /* Overflow. */ - return REDIS_ERR; - if (value != NULL) *value = v; - } - return REDIS_OK; -} - -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) { - long long v; - if (string2ll(p, len, &v) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad integer value"); - return REDIS_ERR; - } - obj = r->fn->createInteger(cur,v); - } 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 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 */ - - if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad bulk string length"); - return REDIS_ERR; - } - - if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bulk string length out of range"); - return REDIS_ERR; - } - - if (len == -1) { - /* 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 long elements; - int root = 0, len; - - /* 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,&len)) != NULL) { - if (string2ll(p, len, &elements) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad multi-bulk length"); - return REDIS_ERR; - } - - root = (r->ridx == 0); - - if (elements < -1 || elements > INT_MAX) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Multi-bulk length out of range"); - return REDIS_ERR; - } - - 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(1,sizeof(redisReader)); - if (r == NULL) - return NULL; - - 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 == NULL) - return; - if (r->reply != NULL && r->fn && r->fn->freeObject) - r->fn->freeObject(r->reply); - 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-0.14.1/read.h b/ext/hiredis-0.14.1/read.h deleted file mode 100644 index 2988aa45..00000000 --- a/ext/hiredis-0.14.1/read.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 occurred. 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... */ - -#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. */ - -#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); - -#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/hiredis-0.14.1/sds.c b/ext/hiredis-0.14.1/sds.c deleted file mode 100644 index 923ffd82..00000000 --- a/ext/hiredis-0.14.1/sds.c +++ /dev/null @@ -1,1272 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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" -#include "sdsalloc.h" - -static inline int sdsHdrSize(char type) { - switch(type&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return sizeof(struct sdshdr5); - case SDS_TYPE_8: - return sizeof(struct sdshdr8); - case SDS_TYPE_16: - return sizeof(struct sdshdr16); - case SDS_TYPE_32: - return sizeof(struct sdshdr32); - case SDS_TYPE_64: - return sizeof(struct sdshdr64); - } - return 0; -} - -static inline char sdsReqType(size_t string_size) { - if (string_size < 32) - return SDS_TYPE_5; - if (string_size < 0xff) - return SDS_TYPE_8; - if (string_size < 0xffff) - return SDS_TYPE_16; - if (string_size < 0xffffffff) - return SDS_TYPE_32; - return SDS_TYPE_64; -} - -/* 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) { - void *sh; - sds s; - char type = sdsReqType(initlen); - /* Empty strings are usually created in order to append. Use type 8 - * since type 5 is not good at this. */ - if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; - int hdrlen = sdsHdrSize(type); - unsigned char *fp; /* flags pointer. */ - - sh = s_malloc(hdrlen+initlen+1); - if (sh == NULL) return NULL; - if (!init) - memset(sh, 0, hdrlen+initlen+1); - s = (char*)sh+hdrlen; - fp = ((unsigned char*)s)-1; - switch(type) { - case SDS_TYPE_5: { - *fp = type | (initlen << SDS_TYPE_BITS); - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - } - if (initlen && init) - memcpy(s, init, initlen); - s[initlen] = '\0'; - return s; -} - -/* 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 terminated 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; - s_free((char*)s-sdsHdrSize(s[-1])); -} - -/* 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) { - int reallen = strlen(s); - sdssetlen(s, reallen); -} - -/* Modify an sds string in-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) { - sdssetlen(s, 0); - s[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) { - void *sh, *newsh; - size_t avail = sdsavail(s); - size_t len, newlen; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - - /* Return ASAP if there is enough space left. */ - if (avail >= addlen) return s; - - len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - newlen = (len+addlen); - if (newlen < SDS_MAX_PREALLOC) - newlen *= 2; - else - newlen += SDS_MAX_PREALLOC; - - type = sdsReqType(newlen); - - /* Don't use type 5: the user is appending to the string and type 5 is - * not able to remember empty space, so sdsMakeRoomFor() must be called - * at every appending operation. */ - if (type == SDS_TYPE_5) type = SDS_TYPE_8; - - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+newlen+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - /* Since the header size changes, need to move the string forward, - * and can't use realloc */ - newsh = s_malloc(hdrlen+newlen+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, newlen); - return s; -} - -/* 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) { - void *sh, *newsh; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - size_t len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - - type = sdsReqType(len); - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+len+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - newsh = s_malloc(hdrlen+len+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, len); - return s; -} - -/* 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) { - size_t alloc = sdsalloc(s); - return sdsHdrSize(s[-1])+alloc+1; -} - -/* Return the pointer of the actual SDS allocation (normally SDS strings - * are referenced by the start of the string buffer). */ -void *sdsAllocPtr(sds s) { - return (void*) (s-sdsHdrSize(s[-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) { - unsigned char flags = s[-1]; - size_t len; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char oldlen = SDS_TYPE_5_LEN(flags); - assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr))); - *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS); - len = oldlen+incr; - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr))); - len = (sh->len += incr); - break; - } - default: len = 0; /* Just to avoid compilation warnings. */ - } - s[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) { - size_t curlen = sdslen(s); - - if (len <= curlen) return s; - s = sdsMakeRoomFor(s,len-curlen); - if (s == NULL) return NULL; - - /* Make sure added region doesn't contain garbage */ - memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ - sdssetlen(s, 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) { - size_t curlen = sdslen(s); - - s = sdsMakeRoomFor(s,len); - if (s == NULL) return NULL; - memcpy(s+curlen, t, len); - sdssetlen(s, curlen+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) { - if (sdsalloc(s) < len) { - s = sdsMakeRoomFor(s,len-sdslen(s)); - if (s == NULL) return NULL; - } - memcpy(s, t, len); - s[len] = '\0'; - sdssetlen(s, 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 length 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; -} - -/* 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[SDS_LLSTR_SIZE]; - int len = sdsll2str(buf,value); - - return sdsnewlen(buf,len); -} - -/* Like sdscatprintf() but gets va_list instead of being variadic. */ -sds sdscatvprintf(sds s, const char *fmt, va_list ap) { - va_list cpy; - char staticbuf[1024], *buf = staticbuf, *t; - size_t buflen = strlen(fmt)*2; - - /* We try to start using a static buffer for speed. - * If not possible we revert to heap allocation. */ - if (buflen > sizeof(staticbuf)) { - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - } else { - buflen = sizeof(staticbuf); - } - - /* Try with buffers two times bigger every time we fail to - * fit the string in the current buffer size. */ - while(1) { - buf[buflen-2] = '\0'; - va_copy(cpy,ap); - vsnprintf(buf, buflen, fmt, cpy); - va_end(cpy); - if (buf[buflen-2] != '\0') { - if (buf != staticbuf) s_free(buf); - buflen *= 2; - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - continue; - } - break; - } - - /* Finally concat the obtained string to the SDS string and return it. */ - t = sdscat(s, buf); - if (buf != staticbuf) s_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) - * %% - Verbatim "%" character. - */ -sds sdscatfmt(sds s, char const *fmt, ...) { - const char *f = fmt; - int i; - va_list ap; - - va_start(ap,fmt); - i = sdslen(s); /* Position of the next byte to write to dest str. */ - while(*f) { - char next, *str; - size_t l; - long long num; - unsigned long long unum; - - /* Make sure there is always space for at least 1 char. */ - if (sdsavail(s)==0) { - s = sdsMakeRoomFor(s,1); - } - - 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 (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - } - memcpy(s+i,str,l); - sdsinclen(s,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 (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - } - memcpy(s+i,buf,l); - sdsinclen(s,l); - i += l; - } - break; - case 'u': - case 'U': - if (next == 'u') - unum = va_arg(ap,unsigned int); - else - unum = va_arg(ap,unsigned long long); - { - char buf[SDS_LLSTR_SIZE]; - l = sdsull2str(buf,unum); - if (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - } - memcpy(s+i,buf,l); - sdsinclen(s,l); - i += l; - } - break; - default: /* Handle %% and generally %. */ - s[i++] = next; - sdsinclen(s,1); - break; - } - break; - default: - s[i++] = *f; - sdsinclen(s,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,"Aa. :"); - * printf("%s\n", s); - * - * Output will be just "Hello World". - */ -sds sdstrim(sds s, const char *cset) { - 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 > sp && strchr(cset, *ep)) ep--; - len = (sp > ep) ? 0 : ((ep-sp)+1); - if (s != sp) memmove(s, sp, len); - s[len] = '\0'; - sdssetlen(s,len); - return s; -} - -/* 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) { - 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(s, s+start, newlen); - s[newlen] = 0; - sdssetlen(s,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: - * - * positive if s1 > s2. - * negative 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 = s_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 = s_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]); - s_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]); - s_free(tokens); -} - -/* 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 = s_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 = s_malloc(sizeof(void*)); - return vector; - } - } - -err: - while((*argc)--) - sdsfree(vector[*argc]); - s_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) { - sds join = sdsempty(); - int j; - - for (j = 0; j < argc; j++) { - join = sdscat(join, argv[j]); - if (j != argc-1) join = sdscat(join,sep); - } - 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; -} - -/* Wrappers to the allocators used by SDS. Note that SDS will actually - * just use the macros defined into sdsalloc.h in order to avoid to pay - * the overhead of function calls. Here we define these wrappers only for - * the programs SDS is linked to, if they want to touch the SDS internals - * even if they use a different allocator. */ -void *sds_malloc(size_t size) { return s_malloc(size); } -void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); } -void sds_free(void *ptr) { s_free(ptr); } - -#if defined(SDS_TEST_MAIN) -#include -#include "testhelp.h" -#include "limits.h" - -#define UNUSED(x) (void)(x) -int sdsTest(void) { - { - 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("--"); - x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX); - test_cond("sdscatfmt() seems working in the base case", - sdslen(x) == 60 && - memcmp(x,"--Hello Hi! World -9223372036854775808," - "9223372036854775807--",60) == 0) - printf("[%s]\n",x); - - sdsfree(x); - x = sdsnew("--"); - x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX); - test_cond("sdscatfmt() seems working with unsigned numbers", - sdslen(x) == 35 && - memcmp(x,"--4294967295,18446744073709551615--",35) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," x"); - test_cond("sdstrim() works when all chars match", - sdslen(x) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," "); - test_cond("sdstrim() works when a single char remains", - sdslen(x) == 1 && x[0] == 'x') - - 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) - - { - unsigned int oldfree; - char *p; - int step = 10, j, i; - - sdsfree(x); - sdsfree(y); - x = sdsnew("0"); - test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0); - - /* Run the test a few times in order to hit the first two - * SDS header types. */ - for (i = 0; i < 10; i++) { - int oldlen = sdslen(x); - x = sdsMakeRoomFor(x,step); - int type = x[-1]&SDS_TYPE_MASK; - - test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen); - if (type != SDS_TYPE_5) { - test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step); - oldfree = sdsavail(x); - } - p = x+oldlen; - for (j = 0; j < step; j++) { - p[j] = 'A'+j; - } - sdsIncrLen(x,step); - } - test_cond("sdsMakeRoomFor() content", - memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0); - test_cond("sdsMakeRoomFor() final length",sdslen(x)==101); - - sdsfree(x); - } - } - test_report() - return 0; -} -#endif - -#ifdef SDS_TEST_MAIN -int main(void) { - return sdsTest(); -} -#endif diff --git a/ext/hiredis-0.14.1/sds.h b/ext/hiredis-0.14.1/sds.h deleted file mode 100644 index 13be75a9..00000000 --- a/ext/hiredis-0.14.1/sds.h +++ /dev/null @@ -1,273 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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 -#include - -typedef char *sds; - -/* Note: sdshdr5 is never used, we just access the flags byte directly. - * However is here to document the layout of type 5 SDS strings. */ -struct __attribute__ ((__packed__)) sdshdr5 { - unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr8 { - uint8_t len; /* used */ - uint8_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr16 { - uint16_t len; /* used */ - uint16_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr32 { - uint32_t len; /* used */ - uint32_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr64 { - uint64_t len; /* used */ - uint64_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; - -#define SDS_TYPE_5 0 -#define SDS_TYPE_8 1 -#define SDS_TYPE_16 2 -#define SDS_TYPE_32 3 -#define SDS_TYPE_64 4 -#define SDS_TYPE_MASK 7 -#define SDS_TYPE_BITS 3 -#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); -#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) -#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) - -static inline size_t sdslen(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->len; - case SDS_TYPE_16: - return SDS_HDR(16,s)->len; - case SDS_TYPE_32: - return SDS_HDR(32,s)->len; - case SDS_TYPE_64: - return SDS_HDR(64,s)->len; - } - return 0; -} - -static inline size_t sdsavail(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - return 0; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - return sh->alloc - sh->len; - } - } - return 0; -} - -static inline void sdssetlen(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len = newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len = newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len = newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len = newlen; - break; - } -} - -static inline void sdsinclen(sds s, size_t inc) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len += inc; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len += inc; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len += inc; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len += inc; - break; - } -} - -/* sdsalloc() = sdsavail() + sdslen() */ -static inline size_t sdsalloc(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->alloc; - case SDS_TYPE_16: - return SDS_HDR(16,s)->alloc; - case SDS_TYPE_32: - return SDS_HDR(32,s)->alloc; - case SDS_TYPE_64: - return SDS_HDR(64,s)->alloc; - } - return 0; -} - -static inline void sdssetalloc(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - /* Nothing to do, this type has no total allocation info. */ - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->alloc = newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->alloc = newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->alloc = newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->alloc = newlen; - break; - } -} - -sds sdsnewlen(const void *init, size_t initlen); -sds sdsnew(const char *init); -sds sdsempty(void); -sds sdsdup(const sds s); -void sdsfree(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, ...); -sds 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); -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); -void *sdsAllocPtr(sds s); - -/* Export the allocator used by SDS to the program using SDS. - * Sometimes the program SDS is linked to, may use a different set of - * allocators, but may want to allocate or free things that SDS will - * respectively free or allocate. */ -void *sds_malloc(size_t size); -void *sds_realloc(void *ptr, size_t size); -void sds_free(void *ptr); - -#ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); -#endif - -#endif diff --git a/ext/hiredis-0.14.1/sdsalloc.h b/ext/hiredis-0.14.1/sdsalloc.h deleted file mode 100644 index f43023c4..00000000 --- a/ext/hiredis-0.14.1/sdsalloc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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. - */ - -/* SDS allocator selection. - * - * This file is used in order to change the SDS allocator at compile time. - * Just define the following defines to what you want to use. Also add - * the include of your alternate allocator if needed (not needed in order - * to use the default libc allocator). */ - -#define s_malloc malloc -#define s_realloc realloc -#define s_free free diff --git a/ext/hiredis-0.14.1/test.c b/ext/hiredis-0.14.1/test.c deleted file mode 100644 index 0f5bfe57..00000000 --- a/ext/hiredis-0.14.1/test.c +++ /dev/null @@ -1,923 +0,0 @@ -#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_sock; -}; - -/* 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_sock.path); - } else if (config.type == CONN_FD) { - /* Create a dummy connection just to get an fd to inherit */ - redisContext *dummy_ctx = redisConnectUnix(config.unix_sock.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); - - sds sds_cmd; - - sds_cmd = sdsempty(); - test("Format command into sds by passing argc/argv without lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL); - test_cond(strncmp(sds_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)); - sdsfree(sds_cmd); - - sds_cmd = sdsempty(); - test("Format command into sds by passing argc/argv with lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens); - test_cond(strncmp(sds_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)); - sdsfree(sds_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("Correctly parses LLONG_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":9223372036854775807\r\n",22); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->integer == LLONG_MAX); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when > LLONG_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":9223372036854775808\r\n",22); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bad integer value") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Correctly parses LLONG_MIN: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":-9223372036854775808\r\n",23); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->integer == LLONG_MIN); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when < LLONG_MIN: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":-9223372036854775809\r\n",23); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bad integer value") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when array < -1: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "*-2\r\n+asdf\r\n",12); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when bulk < -1: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "$-2\r\nasdf\r\n",11); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bulk string length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when array > INT_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - -#if LLONG_MAX > SIZE_MAX - test("Set error when bulk > SIZE_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bulk string length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); -#endif - - 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 *redisCtx = NULL; - void *reply = NULL; - - test("Don't fail when redisFree is passed a NULL value: "); - redisFree(redisCtx); - test_cond(redisCtx == 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,"hostname nor servname provided, or not known") == 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_sock 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_sock.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 && strcmp(c->errstr, "Invalid timeout specified") == 0); - 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 && strcmp(c->errstr, "Invalid timeout specified") == 0); - 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); - - replies = malloc(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx INCRBY: %.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); - - replies = malloc(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"INCRBY incrkey %d", 1000000); - 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_INTEGER); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx INCRBY (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_sock = { - .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_sock.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_sock.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_sock.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-0.14.1/win32.h b/ext/hiredis-0.14.1/win32.h deleted file mode 100644 index 1a27c18f..00000000 --- a/ext/hiredis-0.14.1/win32.h +++ /dev/null @@ -1,42 +0,0 @@ -#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/hiredis-1.0.2/.gitignore b/ext/hiredis-1.0.2/.gitignore deleted file mode 100644 index 056959ff..00000000 --- a/ext/hiredis-1.0.2/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -/hiredis-test -/examples/hiredis-example* -/*.o -/*.so -/*.dylib -/*.a -/*.pc -*.dSYM -tags diff --git a/ext/hiredis-1.0.2/.travis.yml b/ext/hiredis-1.0.2/.travis.yml deleted file mode 100644 index f9a9460f..00000000 --- a/ext/hiredis-1.0.2/.travis.yml +++ /dev/null @@ -1,131 +0,0 @@ -language: c -compiler: - - gcc - - clang - -os: - - linux - - osx - -dist: bionic - -branches: - only: - - staging - - trying - - master - - /^release\/.*$/ - -install: - - if [ "$BITS" == "64" ]; then - wget https://github.com/redis/redis/archive/6.0.6.tar.gz; - tar -xzvf 6.0.6.tar.gz; - pushd redis-6.0.6 && BUILD_TLS=yes make && export PATH=$PWD/src:$PATH && popd; - fi - -before_script: - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then - curl -O https://distfiles.macports.org/MacPorts/MacPorts-2.6.2-10.13-HighSierra.pkg; - sudo installer -pkg MacPorts-2.6.2-10.13-HighSierra.pkg -target /; - export PATH=$PATH:/opt/local/bin && sudo port -v selfupdate; - sudo port -N install openssl redis; - fi; - -addons: - apt: - sources: - - sourceline: 'ppa:chris-lea/redis-server' - packages: - - libc6-dbg - - libc6-dev - - libc6:i386 - - libc6-dev-i386 - - libc6-dbg:i386 - - gcc-multilib - - g++-multilib - - libssl-dev - - libssl-dev:i386 - - valgrind - - redis - -env: - - BITS="32" - - BITS="64" - -script: - - EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON"; - if [ "$BITS" == "64" ]; then - EXTRA_CMAKE_OPTS="$EXTRA_CMAKE_OPTS -DENABLE_SSL_TESTS:BOOL=ON"; - fi; - if [ "$TRAVIS_OS_NAME" == "osx" ]; then - if [ "$BITS" == "32" ]; then - CFLAGS="-m32 -Werror"; - CXXFLAGS="-m32 -Werror"; - LDFLAGS="-m32"; - EXTRA_CMAKE_OPTS=; - else - CFLAGS="-Werror"; - CXXFLAGS="-Werror"; - fi; - else - TEST_PREFIX="valgrind --track-origins=yes --leak-check=full"; - if [ "$BITS" == "32" ]; then - CFLAGS="-m32 -Werror"; - CXXFLAGS="-m32 -Werror"; - LDFLAGS="-m32"; - EXTRA_CMAKE_OPTS=; - else - CFLAGS="-Werror"; - CXXFLAGS="-Werror"; - fi; - fi; - export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS - - make && make clean; - if [ "$TRAVIS_OS_NAME" == "osx" ]; then - if [ "$BITS" == "64" ]; then - OPENSSL_PREFIX="$(ls -d /usr/local/Cellar/openssl@1.1/*)" USE_SSL=1 make; - fi; - else - USE_SSL=1 make; - fi; - - mkdir build/ && cd build/ - - cmake .. ${EXTRA_CMAKE_OPTS} - - make VERBOSE=1 - - if [ "$BITS" == "64" ]; then - TEST_SSL=1 SKIPS_AS_FAILS=1 ctest -V; - else - SKIPS_AS_FAILS=1 ctest -V; - fi; - -jobs: - include: - # Windows MinGW cross compile on Linux - - os: linux - dist: xenial - compiler: mingw - addons: - apt: - packages: - - ninja-build - - gcc-mingw-w64-x86-64 - - g++-mingw-w64-x86-64 - script: - - mkdir build && cd build - - CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on - - ninja -v - - # Windows MSVC 2017 - - os: windows - compiler: msvc - env: - - MATRIX_EVAL="CC=cl.exe && CXX=cl.exe" - before_install: - - eval "${MATRIX_EVAL}" - install: - - choco install ninja - - choco install -y memurai-developer - script: - - mkdir build && cd build - - cmd.exe //C 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat' amd64 '&&' - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DENABLE_EXAMPLES=ON '&&' ninja -v - - ./hiredis-test.exe diff --git a/ext/hiredis-1.0.2/CHANGELOG.md b/ext/hiredis-1.0.2/CHANGELOG.md deleted file mode 100644 index 2a2bc314..00000000 --- a/ext/hiredis-1.0.2/CHANGELOG.md +++ /dev/null @@ -1,364 +0,0 @@ -## [1.0.2](https://github.com/redis/hiredis/tree/v1.0.2) - (2021-10-07) - -Announcing Hiredis v1.0.2, which fixes CVE-2021-32765 but returns the SONAME to the correct value of `1.0.0`. - -- [Revert SONAME bump](https://github.com/redis/hiredis/commit/d4e6f109a064690cde64765c654e679fea1d3548) - ([Michael Grunder](https://github.com/michael-grunder)) - -## [1.0.1](https://github.com/redis/hiredis/tree/v1.0.1) - (2021-10-04) - -This release erroneously bumped the SONAME, please use [1.0.2](https://github.com/redis/hiredis/tree/v1.0.2) - -Announcing Hiredis v1.0.1, a security release fixing CVE-2021-32765 - -- Fix for [CVE-2021-32765](https://github.com/redis/hiredis/security/advisories/GHSA-hfm9-39pp-55p2) - [commit](https://github.com/redis/hiredis/commit/76a7b10005c70babee357a7d0f2becf28ec7ed1e) - ([Yossi Gottlieb](https://github.com/yossigo)) - -_Thanks to [Yossi Gottlieb](https://github.com/yossigo) for the security fix and to [Microsoft Security Vulnerability Research](https://www.microsoft.com/en-us/msrc/msvr) for finding the bug._ :sparkling_heart: - -## [1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) - (2020-08-03) - -Announcing Hiredis v1.0.0, which adds support for RESP3, SSL connections, allocator injection, and better Windows support! :tada: - -_A big thanks to everyone who helped with this release. The following list includes everyone who contributed at least five lines, sorted by lines contributed._ :sparkling_heart: - -[Michael Grunder](https://github.com/michael-grunder), [Yossi Gottlieb](https://github.com/yossigo), -[Mark Nunberg](https://github.com/mnunberg), [Marcus Geelnard](https://github.com/mbitsnbites), -[Justin Brewer](https://github.com/justinbrewer), [Valentino Geron](https://github.com/valentinogeron), -[Minun Dragonation](https://github.com/dragonation), [Omri Steiner](https://github.com/OmriSteiner), -[Sangmoon Yi](https://github.com/jman-krafton), [Jinjiazh](https://github.com/jinjiazhang), -[Odin Hultgren Van Der Horst](https://github.com/Miniwoffer), [Muhammad Zahalqa](https://github.com/tryfinally), -[Nick Rivera](https://github.com/heronr), [Qi Yang](https://github.com/movebean), -[kevin1018](https://github.com/kevin1018) - -[Full Changelog](https://github.com/redis/hiredis/compare/v0.14.1...v1.0.0) - -**BREAKING CHANGES**: - -* `redisOptions` now has two timeout fields. One for connecting, and one for commands. If you're presently using `options->timeout` you will need to change it to use `options->connect_timeout`. (See [example](https://github.com/redis/hiredis/commit/38b5ae543f5c99eb4ccabbe277770fc6bc81226f#diff-86ba39d37aa829c8c82624cce4f049fbL36)) - -* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now protocol errors. This is consistent - with the RESP specification. On 32-bit platforms, the upper bound is lowered to `SIZE_MAX`. - -* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter. - -**New features:** -- Support for RESP3 - [\#697](https://github.com/redis/hiredis/pull/697), - [\#805](https://github.com/redis/hiredis/pull/805), - [\#819](https://github.com/redis/hiredis/pull/819), - [\#841](https://github.com/redis/hiredis/pull/841) - ([Yossi Gottlieb](https://github.com/yossigo), [Michael Grunder](https://github.com/michael-grunder)) -- Support for SSL connections - [\#645](https://github.com/redis/hiredis/pull/645), - [\#699](https://github.com/redis/hiredis/pull/699), - [\#702](https://github.com/redis/hiredis/pull/702), - [\#708](https://github.com/redis/hiredis/pull/708), - [\#711](https://github.com/redis/hiredis/pull/711), - [\#821](https://github.com/redis/hiredis/pull/821), - [more](https://github.com/redis/hiredis/pulls?q=is%3Apr+is%3Amerged+SSL) - ([Mark Nunberg](https://github.com/mnunberg), [Yossi Gottlieb](https://github.com/yossigo)) -- Run-time allocator injection - [\#800](https://github.com/redis/hiredis/pull/800) - ([Michael Grunder](https://github.com/michael-grunder)) -- Improved Windows support (including MinGW and Windows CI) - [\#652](https://github.com/redis/hiredis/pull/652), - [\#663](https://github.com/redis/hiredis/pull/663) - ([Marcus Geelnard](https://www.bitsnbites.eu/author/m/)) -- Adds support for distinct connect and command timeouts - [\#839](https://github.com/redis/hiredis/pull/839), - [\#829](https://github.com/redis/hiredis/pull/829) - ([Valentino Geron](https://github.com/valentinogeron)) -- Add generic pointer and destructor to `redisContext` that users can use for context. - [\#855](https://github.com/redis/hiredis/pull/855) - ([Michael Grunder](https://github.com/michael-grunder)) - -**Closed issues (that involved code changes):** - -- Makefile does not install TLS libraries [\#809](https://github.com/redis/hiredis/issues/809) -- redisConnectWithOptions should not set command timeout [\#722](https://github.com/redis/hiredis/issues/722), [\#829](https://github.com/redis/hiredis/pull/829) ([valentinogeron](https://github.com/valentinogeron)) -- Fix integer overflow in `sdsrange` [\#827](https://github.com/redis/hiredis/issues/827) -- INFO & CLUSTER commands failed when using RESP3 [\#802](https://github.com/redis/hiredis/issues/802) -- Windows compatibility patches [\#687](https://github.com/redis/hiredis/issues/687), [\#838](https://github.com/redis/hiredis/issues/838), [\#842](https://github.com/redis/hiredis/issues/842) -- RESP3 PUSH messages incorrectly use pending callback [\#825](https://github.com/redis/hiredis/issues/825) -- Asynchronous PSUBSCRIBE command fails when using RESP3 [\#815](https://github.com/redis/hiredis/issues/815) -- New SSL API [\#804](https://github.com/redis/hiredis/issues/804), [\#813](https://github.com/redis/hiredis/issues/813) -- Hard-coded limit of nested reply depth [\#794](https://github.com/redis/hiredis/issues/794) -- Fix TCP_NODELAY in Windows/OSX [\#679](https://github.com/redis/hiredis/issues/679), [\#690](https://github.com/redis/hiredis/issues/690), [\#779](https://github.com/redis/hiredis/issues/779), [\#785](https://github.com/redis/hiredis/issues/785), -- Added timers to libev adapter. [\#778](https://github.com/redis/hiredis/issues/778), [\#795](https://github.com/redis/hiredis/pull/795) -- Initialization discards const qualifier [\#777](https://github.com/redis/hiredis/issues/777) -- \[BUG\]\[MinGW64\] Error setting socket timeout [\#775](https://github.com/redis/hiredis/issues/775) -- undefined reference to hi_malloc [\#769](https://github.com/redis/hiredis/issues/769) -- hiredis pkg-config file incorrectly ignores multiarch libdir spec'n [\#767](https://github.com/redis/hiredis/issues/767) -- Don't use -G to build shared object on Solaris [\#757](https://github.com/redis/hiredis/issues/757) -- error when make USE\_SSL=1 [\#748](https://github.com/redis/hiredis/issues/748) -- Allow to change SSL Mode [\#646](https://github.com/redis/hiredis/issues/646) -- hiredis/adapters/libevent.h memleak [\#618](https://github.com/redis/hiredis/issues/618) -- redisLibuvPoll crash when server closes the connetion [\#545](https://github.com/redis/hiredis/issues/545) -- about redisAsyncDisconnect question [\#518](https://github.com/redis/hiredis/issues/518) -- hiredis adapters libuv error for help [\#508](https://github.com/redis/hiredis/issues/508) -- API/ABI changes analysis [\#506](https://github.com/redis/hiredis/issues/506) -- Memory leak patch in Redis [\#502](https://github.com/redis/hiredis/issues/502) -- Remove the depth limitation [\#421](https://github.com/redis/hiredis/issues/421) - -**Merged pull requests:** - -- Move SSL management to a distinct private pointer [\#855](https://github.com/redis/hiredis/pull/855) ([michael-grunder](https://github.com/michael-grunder)) -- Move include to sockcompat.h to maintain style [\#850](https://github.com/redis/hiredis/pull/850) ([michael-grunder](https://github.com/michael-grunder)) -- Remove erroneous tag and add license to push example [\#849](https://github.com/redis/hiredis/pull/849) ([michael-grunder](https://github.com/michael-grunder)) -- fix windows compiling with mingw [\#848](https://github.com/redis/hiredis/pull/848) ([rmalizia44](https://github.com/rmalizia44)) -- Some Windows quality of life improvements. [\#846](https://github.com/redis/hiredis/pull/846) ([michael-grunder](https://github.com/michael-grunder)) -- Use \_WIN32 define instead of WIN32 [\#845](https://github.com/redis/hiredis/pull/845) ([michael-grunder](https://github.com/michael-grunder)) -- Non Linux CI fixes [\#844](https://github.com/redis/hiredis/pull/844) ([michael-grunder](https://github.com/michael-grunder)) -- Resp3 oob push support [\#841](https://github.com/redis/hiredis/pull/841) ([michael-grunder](https://github.com/michael-grunder)) -- fix \#785: defer TCP\_NODELAY in async tcp connections [\#836](https://github.com/redis/hiredis/pull/836) ([OmriSteiner](https://github.com/OmriSteiner)) -- sdsrange overflow fix [\#830](https://github.com/redis/hiredis/pull/830) ([michael-grunder](https://github.com/michael-grunder)) -- Use explicit pointer casting for c++ compatibility [\#826](https://github.com/redis/hiredis/pull/826) ([aureus1](https://github.com/aureus1)) -- Document allocator injection and completeness fix in test.c [\#824](https://github.com/redis/hiredis/pull/824) ([michael-grunder](https://github.com/michael-grunder)) -- Use unique names for allocator struct members [\#823](https://github.com/redis/hiredis/pull/823) ([michael-grunder](https://github.com/michael-grunder)) -- New SSL API to replace redisSecureConnection\(\). [\#821](https://github.com/redis/hiredis/pull/821) ([yossigo](https://github.com/yossigo)) -- Add logic to handle RESP3 push messages [\#819](https://github.com/redis/hiredis/pull/819) ([michael-grunder](https://github.com/michael-grunder)) -- Use standrad isxdigit instead of custom helper function. [\#814](https://github.com/redis/hiredis/pull/814) ([tryfinally](https://github.com/tryfinally)) -- Fix missing SSL build/install options. [\#812](https://github.com/redis/hiredis/pull/812) ([yossigo](https://github.com/yossigo)) -- Add link to ABI tracker [\#808](https://github.com/redis/hiredis/pull/808) ([michael-grunder](https://github.com/michael-grunder)) -- Resp3 verbatim string support [\#805](https://github.com/redis/hiredis/pull/805) ([michael-grunder](https://github.com/michael-grunder)) -- Allow users to replace allocator and handle OOM everywhere. [\#800](https://github.com/redis/hiredis/pull/800) ([michael-grunder](https://github.com/michael-grunder)) -- Remove nested depth limitation. [\#797](https://github.com/redis/hiredis/pull/797) ([michael-grunder](https://github.com/michael-grunder)) -- Attempt to fix compilation on Solaris [\#796](https://github.com/redis/hiredis/pull/796) ([michael-grunder](https://github.com/michael-grunder)) -- Support timeouts in libev adapater [\#795](https://github.com/redis/hiredis/pull/795) ([michael-grunder](https://github.com/michael-grunder)) -- Fix pkgconfig when installing to a custom lib dir [\#793](https://github.com/redis/hiredis/pull/793) ([michael-grunder](https://github.com/michael-grunder)) -- Fix USE\_SSL=1 make/cmake on OSX and CMake tests [\#789](https://github.com/redis/hiredis/pull/789) ([michael-grunder](https://github.com/michael-grunder)) -- Use correct libuv call on Windows [\#784](https://github.com/redis/hiredis/pull/784) ([michael-grunder](https://github.com/michael-grunder)) -- Added CMake package config and fixed hiredis\_ssl on Windows [\#783](https://github.com/redis/hiredis/pull/783) ([michael-grunder](https://github.com/michael-grunder)) -- CMake: Set hiredis\_ssl shared object version. [\#780](https://github.com/redis/hiredis/pull/780) ([yossigo](https://github.com/yossigo)) -- Win32 tests and timeout fix [\#776](https://github.com/redis/hiredis/pull/776) ([michael-grunder](https://github.com/michael-grunder)) -- Provides an optional cleanup callback for async data. [\#768](https://github.com/redis/hiredis/pull/768) ([heronr](https://github.com/heronr)) -- Housekeeping fixes [\#764](https://github.com/redis/hiredis/pull/764) ([michael-grunder](https://github.com/michael-grunder)) -- install alloc.h [\#756](https://github.com/redis/hiredis/pull/756) ([ch1aki](https://github.com/ch1aki)) -- fix spelling mistakes [\#746](https://github.com/redis/hiredis/pull/746) ([ShooterIT](https://github.com/ShooterIT)) -- Free the reply in redisGetReply when passed NULL [\#741](https://github.com/redis/hiredis/pull/741) ([michael-grunder](https://github.com/michael-grunder)) -- Fix dead code in sslLogCallback relating to should\_log variable. [\#737](https://github.com/redis/hiredis/pull/737) ([natoscott](https://github.com/natoscott)) -- Fix typo in dict.c. [\#731](https://github.com/redis/hiredis/pull/731) ([Kevin-Xi](https://github.com/Kevin-Xi)) -- Adding an option to DISABLE\_TESTS [\#727](https://github.com/redis/hiredis/pull/727) ([pbotros](https://github.com/pbotros)) -- Update README with SSL support. [\#720](https://github.com/redis/hiredis/pull/720) ([yossigo](https://github.com/yossigo)) -- Fixes leaks in unit tests [\#715](https://github.com/redis/hiredis/pull/715) ([michael-grunder](https://github.com/michael-grunder)) -- SSL Tests [\#711](https://github.com/redis/hiredis/pull/711) ([yossigo](https://github.com/yossigo)) -- SSL Reorganization [\#708](https://github.com/redis/hiredis/pull/708) ([yossigo](https://github.com/yossigo)) -- Fix MSVC build. [\#706](https://github.com/redis/hiredis/pull/706) ([yossigo](https://github.com/yossigo)) -- SSL: Properly report SSL\_connect\(\) errors. [\#702](https://github.com/redis/hiredis/pull/702) ([yossigo](https://github.com/yossigo)) -- Silent SSL trace to stdout by default. [\#699](https://github.com/redis/hiredis/pull/699) ([yossigo](https://github.com/yossigo)) -- Port RESP3 support from Redis. [\#697](https://github.com/redis/hiredis/pull/697) ([yossigo](https://github.com/yossigo)) -- Removed whitespace before newline [\#691](https://github.com/redis/hiredis/pull/691) ([Miniwoffer](https://github.com/Miniwoffer)) -- Add install adapters header files [\#688](https://github.com/redis/hiredis/pull/688) ([kevin1018](https://github.com/kevin1018)) -- Remove unnecessary null check before free [\#684](https://github.com/redis/hiredis/pull/684) ([qlyoung](https://github.com/qlyoung)) -- redisReaderGetReply leak memory [\#671](https://github.com/redis/hiredis/pull/671) ([movebean](https://github.com/movebean)) -- fix timeout code in windows [\#670](https://github.com/redis/hiredis/pull/670) ([jman-krafton](https://github.com/jman-krafton)) -- test: fix errstr matching for musl libc [\#665](https://github.com/redis/hiredis/pull/665) ([ghost](https://github.com/ghost)) -- Windows: MinGW fixes and Windows Travis builders [\#663](https://github.com/redis/hiredis/pull/663) ([mbitsnbites](https://github.com/mbitsnbites)) -- The setsockopt and getsockopt API diffs from BSD socket and WSA one [\#662](https://github.com/redis/hiredis/pull/662) ([dragonation](https://github.com/dragonation)) -- Fix Compile Error On Windows \(Visual Studio\) [\#658](https://github.com/redis/hiredis/pull/658) ([jinjiazhang](https://github.com/jinjiazhang)) -- Fix NXDOMAIN test case [\#653](https://github.com/redis/hiredis/pull/653) ([michael-grunder](https://github.com/michael-grunder)) -- Add MinGW support [\#652](https://github.com/redis/hiredis/pull/652) ([mbitsnbites](https://github.com/mbitsnbites)) -- SSL Support [\#645](https://github.com/redis/hiredis/pull/645) ([mnunberg](https://github.com/mnunberg)) -- Fix Invalid argument after redisAsyncConnectUnix [\#644](https://github.com/redis/hiredis/pull/644) ([codehz](https://github.com/codehz)) -- Makefile: use predefined AR [\#632](https://github.com/redis/hiredis/pull/632) ([Mic92](https://github.com/Mic92)) -- FreeBSD build fix [\#628](https://github.com/redis/hiredis/pull/628) ([devnexen](https://github.com/devnexen)) -- Fix errors not propagating properly with libuv.h. [\#624](https://github.com/redis/hiredis/pull/624) ([yossigo](https://github.com/yossigo)) -- Update README.md [\#621](https://github.com/redis/hiredis/pull/621) ([Crunsher](https://github.com/Crunsher)) -- Fix redisBufferRead documentation [\#620](https://github.com/redis/hiredis/pull/620) ([hacst](https://github.com/hacst)) -- Add CPPFLAGS to REAL\_CFLAGS [\#614](https://github.com/redis/hiredis/pull/614) ([thomaslee](https://github.com/thomaslee)) -- Update createArray to take size\_t [\#597](https://github.com/redis/hiredis/pull/597) ([justinbrewer](https://github.com/justinbrewer)) -- fix common realloc mistake and add null check more [\#580](https://github.com/redis/hiredis/pull/580) ([charsyam](https://github.com/charsyam)) -- Proper error reporting for connect failures [\#578](https://github.com/redis/hiredis/pull/578) ([mnunberg](https://github.com/mnunberg)) - -\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* - -## [1.0.0-rc1](https://github.com/redis/hiredis/tree/v1.0.0-rc1) - (2020-07-29) - -_Note: There were no changes to code between v1.0.0-rc1 and v1.0.0 so see v1.0.0 for changelog_ - -### 0.14.1 (2020-03-13) - -* Adds safe allocation wrappers (CVE-2020-7105, #747, #752) (Michael Grunder) - -### 0.14.0 (2018-09-25) -**BREAKING CHANGES**: - -* Change `redisReply.len` to `size_t`, as it denotes the the size of a string - - User code should compare this to `size_t` values as well. - If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before. - -* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b]) -* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537]) -* Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622]) -* Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8]) -* Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8]) -* Fix bulk and multi-bulk length truncation (Justin Brewer [109197]) -* Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94]) -* Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6]) -* Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1]) -* Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b]) -* Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96]) -* Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234]) -* Don't send negative values to `__redisAsyncCommand` (Frederik Deweerdt [706129]) -* Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c]) -* Fix libevent leak (zfz [515228]) -* Clean up GCC warning (Ichito Nagata [2ec774]) -* Keep track of errno in `__redisSetErrorFromErrno()` as snprintf may use it (Jin Qing [25cd88]) -* Solaris compilation fix (Donald Whyte [41b07d]) -* Reorder linker arguments when building examples (Tustfarm-heart [06eedd]) -* Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999]) -* libuv use after free fix (Paul Scott [cbb956]) -* Properly close socket fd on reconnect attempt (WSL [64d1ec]) -* Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78]) -* Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5]) -* Update libevent (Chris Xin [386802]) -* Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e]) -* Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6]) -* Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3]) -* Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb]) -* Compatibility fix for strerror_r (Tom Lee [bb1747]) -* Properly detect integer parse/overflow errors (Justin Brewer [93421f]) -* Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40]) -* Catch a buffer overflow when formatting the error message -* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13 -* Fix warnings, when compiled with -Wshadow -* Make hiredis compile in Cygwin on Windows, now CI-tested -* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now - protocol errors. This is consistent with the RESP specification. On 32-bit - platforms, the upper bound is lowered to `SIZE_MAX`. - -* Remove backwards compatibility macro's - -This removes the following old function aliases, use the new name now: - -| Old | New | -| --------------------------- | ---------------------- | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderFree | redisReaderFree | -| redisReplyReaderFeed | redisReaderFeed | -| redisReplyReaderGetReply | redisReaderGetReply | -| redisReplyReaderSetPrivdata | redisReaderSetPrivdata | -| redisReplyReaderGetObject | redisReaderGetObject | -| redisReplyReaderGetError | redisReaderGetError | - -* The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS` - -Previously it broke some builds for people that had `DEBUG` set to some arbitrary value, -due to debugging other software. -By renaming we avoid unintentional name clashes. - -Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again. - -### 0.13.3 (2015-09-16) - -* Revert "Clear `REDIS_CONNECTED` flag when connection is closed". -* Make tests pass on FreeBSD (Thanks, Giacomo Olgeni) - - -If the `REDIS_CONNECTED` flag is cleared, -the async onDisconnect callback function will never be called. -This causes problems as the disconnect is never reported back to the user. - -### 0.13.2 (2015-08-25) - -* Prevent crash on pending replies in async code (Thanks, @switch-st) -* Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs) -* Add MacOS X addapter (Thanks, @dizzus) -* Add Qt adapter (Thanks, Pietro Cerutti) -* Add Ivykis adapter (Thanks, Gergely Nagy) - -All adapters are provided as is and are only tested where possible. - -### 0.13.1 (2015-05-03) - -This is a bug fix release. -The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code. -Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects. -Other non-C99 code can now use hiredis as usual again. -Sorry for the inconvenience. - -* Fix memory leak in async reply handling (Salvatore Sanfilippo) -* Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa) - -### 0.13.0 (2015-04-16) - -This release adds a minimal Windows compatibility layer. -The parser, standalone since v0.12.0, can now be compiled on Windows -(and thus used in other client libraries as well) - -* Windows compatibility layer for parser code (tzickel) -* Properly escape data printed to PKGCONF file (Dan Skorupski) -* Fix tests when assert() undefined (Keith Bennett, Matt Stancliff) -* Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra) - -### 0.12.1 (2015-01-26) - -* Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location -* Fix `make test` as 32 bit build on 64 bit platform - -### 0.12.0 (2015-01-22) - -* Add optional KeepAlive support - -* Try again on EINTR errors - -* Add libuv adapter - -* Add IPv6 support - -* Remove possibility of multiple close on same fd - -* Add ability to bind source address on connect - -* Add redisConnectFd() and redisFreeKeepFd() - -* Fix getaddrinfo() memory leak - -* Free string if it is unused (fixes memory leak) - -* Improve redisAppendCommandArgv performance 2.5x - -* Add support for SO_REUSEADDR - -* Fix redisvFormatCommand format parsing - -* Add GLib 2.0 adapter - -* Refactor reading code into read.c - -* Fix errno error buffers to not clobber errors - -* Generate pkgconf during build - -* Silence _BSD_SOURCE warnings - -* Improve digit counting for multibulk creation - - -### 0.11.0 - -* Increase the maximum multi-bulk reply depth to 7. - -* Increase the read buffer size from 2k to 16k. - -* Use poll(2) instead of select(2) to support large fds (>= 1024). - -### 0.10.1 - -* Makefile overhaul. Important to check out if you override one or more - variables using environment variables or via arguments to the "make" tool. - -* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements - being created by the default reply object functions. - -* Issue #43: Don't crash in an asynchronous context when Redis returns an error - reply after the connection has been made (this happens when the maximum - number of connections is reached). - -### 0.10.0 - -* See commit log. diff --git a/ext/hiredis-1.0.2/CMakeLists.txt b/ext/hiredis-1.0.2/CMakeLists.txt deleted file mode 100644 index f86c9b70..00000000 --- a/ext/hiredis-1.0.2/CMakeLists.txt +++ /dev/null @@ -1,165 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.4.0) -INCLUDE(GNUInstallDirs) -PROJECT(hiredis) - -OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF) -OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF) -OPTION(ENABLE_SSL_TESTS, "Should we test SSL connections" OFF) - -MACRO(getVersionBit name) - SET(VERSION_REGEX "^#define ${name} (.+)$") - FILE(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/hiredis.h" - VERSION_BIT REGEX ${VERSION_REGEX}) - STRING(REGEX REPLACE ${VERSION_REGEX} "\\1" ${name} "${VERSION_BIT}") -ENDMACRO(getVersionBit) - -getVersionBit(HIREDIS_MAJOR) -getVersionBit(HIREDIS_MINOR) -getVersionBit(HIREDIS_PATCH) -getVersionBit(HIREDIS_SONAME) -SET(VERSION "${HIREDIS_MAJOR}.${HIREDIS_MINOR}.${HIREDIS_PATCH}") -MESSAGE("Detected version: ${VERSION}") - -PROJECT(hiredis VERSION "${VERSION}") - -SET(ENABLE_EXAMPLES OFF CACHE BOOL "Enable building hiredis examples") - -SET(hiredis_sources - alloc.c - async.c - dict.c - hiredis.c - net.c - read.c - sds.c - sockcompat.c) - -SET(hiredis_sources ${hiredis_sources}) - -IF(WIN32) - ADD_COMPILE_DEFINITIONS(_CRT_SECURE_NO_WARNINGS WIN32_LEAN_AND_MEAN) -ENDIF() - -ADD_LIBRARY(hiredis SHARED ${hiredis_sources}) - -SET_TARGET_PROPERTIES(hiredis - PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE - VERSION "${HIREDIS_SONAME}") -IF(WIN32 OR MINGW) - TARGET_LINK_LIBRARIES(hiredis PRIVATE ws2_32) -ENDIF() - -TARGET_INCLUDE_DIRECTORIES(hiredis PUBLIC $ $) - -CONFIGURE_FILE(hiredis.pc.in hiredis.pc @ONLY) - -INSTALL(TARGETS hiredis - EXPORT hiredis-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -INSTALL(FILES hiredis.h read.h sds.h async.h alloc.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) - -INSTALL(DIRECTORY adapters - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) - -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - -export(EXPORT hiredis-targets - FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis-targets.cmake" - NAMESPACE hiredis::) - -SET(CMAKE_CONF_INSTALL_DIR share/hiredis) -SET(INCLUDE_INSTALL_DIR include) -include(CMakePackageConfigHelpers) -configure_package_config_file(hiredis-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake - INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR} - PATH_VARS INCLUDE_INSTALL_DIR) - -INSTALL(EXPORT hiredis-targets - FILE hiredis-targets.cmake - NAMESPACE hiredis:: - DESTINATION ${CMAKE_CONF_INSTALL_DIR}) - -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis-config.cmake - DESTINATION ${CMAKE_CONF_INSTALL_DIR}) - - -IF(ENABLE_SSL) - IF (NOT OPENSSL_ROOT_DIR) - IF (APPLE) - SET(OPENSSL_ROOT_DIR "/usr/local/opt/openssl") - ENDIF() - ENDIF() - FIND_PACKAGE(OpenSSL REQUIRED) - SET(hiredis_ssl_sources - ssl.c) - ADD_LIBRARY(hiredis_ssl SHARED - ${hiredis_ssl_sources}) - - IF (APPLE) - SET_PROPERTY(TARGET hiredis_ssl PROPERTY LINK_FLAGS "-Wl,-undefined -Wl,dynamic_lookup") - ENDIF() - - SET_TARGET_PROPERTIES(hiredis_ssl - PROPERTIES - WINDOWS_EXPORT_ALL_SYMBOLS TRUE - VERSION "${HIREDIS_SONAME}") - - TARGET_INCLUDE_DIRECTORIES(hiredis_ssl PRIVATE "${OPENSSL_INCLUDE_DIR}") - TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE ${OPENSSL_LIBRARIES}) - IF (WIN32 OR MINGW) - TARGET_LINK_LIBRARIES(hiredis_ssl PRIVATE hiredis) - ENDIF() - CONFIGURE_FILE(hiredis_ssl.pc.in hiredis_ssl.pc @ONLY) - - INSTALL(TARGETS hiredis_ssl - EXPORT hiredis_ssl-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - - INSTALL(FILES hiredis_ssl.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hiredis) - - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - - export(EXPORT hiredis_ssl-targets - FILE "${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-targets.cmake" - NAMESPACE hiredis::) - - SET(CMAKE_CONF_INSTALL_DIR share/hiredis_ssl) - configure_package_config_file(hiredis_ssl-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake - INSTALL_DESTINATION ${CMAKE_CONF_INSTALL_DIR} - PATH_VARS INCLUDE_INSTALL_DIR) - - INSTALL(EXPORT hiredis_ssl-targets - FILE hiredis_ssl-targets.cmake - NAMESPACE hiredis:: - DESTINATION ${CMAKE_CONF_INSTALL_DIR}) - - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hiredis_ssl-config.cmake - DESTINATION ${CMAKE_CONF_INSTALL_DIR}) -ENDIF() - -IF(NOT DISABLE_TESTS) - ENABLE_TESTING() - ADD_EXECUTABLE(hiredis-test test.c) - IF(ENABLE_SSL_TESTS) - ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1) - TARGET_LINK_LIBRARIES(hiredis-test hiredis hiredis_ssl) - ELSE() - TARGET_LINK_LIBRARIES(hiredis-test hiredis) - ENDIF() - ADD_TEST(NAME hiredis-test - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh) -ENDIF() - -# Add examples -IF(ENABLE_EXAMPLES) - ADD_SUBDIRECTORY(examples) -ENDIF(ENABLE_EXAMPLES) diff --git a/ext/hiredis-1.0.2/COPYING b/ext/hiredis-1.0.2/COPYING deleted file mode 100644 index a5fc9739..00000000 --- a/ext/hiredis-1.0.2/COPYING +++ /dev/null @@ -1,29 +0,0 @@ -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-1.0.2/Makefile b/ext/hiredis-1.0.2/Makefile deleted file mode 100644 index a8d37a2e..00000000 --- a/ext/hiredis-1.0.2/Makefile +++ /dev/null @@ -1,308 +0,0 @@ -# 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=alloc.o net.o hiredis.o sds.o async.o read.o sockcompat.o -SSL_OBJ=ssl.o -EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib hiredis-example-push -ifeq ($(USE_SSL),1) -EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl -endif -TESTS=hiredis-test -LIBNAME=libhiredis -PKGCONFNAME=hiredis.pc -SSL_LIBNAME=libhiredis_ssl -SSL_PKGCONFNAME=hiredis_ssl.pc - -HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}') -HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}') -HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}') -HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}') - -# Installation related variables and target -PREFIX?=/usr/local -INCLUDE_PATH?=include/hiredis -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') -CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++') -OPTIMIZATION?=-O3 -WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -DEBUG_FLAGS?= -g -ggdb -REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) -REAL_LDFLAGS=$(LDFLAGS) - -DYLIBSUFFIX=so -STLIBSUFFIX=a -DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) -DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR) -DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) - -DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) -STLIB_MAKE_CMD=$(AR) rcs - -SSL_DYLIB_MINOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) -SSL_DYLIB_MAJOR_NAME=$(SSL_LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR) -SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX) -SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX) -SSL_DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(SSL_DYLIB_MINOR_NAME) - -# Platform-specific overrides -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') - -USE_SSL?=0 - -# This is required for test.c only -ifeq ($(USE_SSL),1) - CFLAGS+=-DHIREDIS_TEST_SSL -endif - -ifeq ($(uname_S),Linux) - SSL_LDFLAGS=-lssl -lcrypto -else - OPENSSL_PREFIX?=/usr/local/opt/openssl - CFLAGS+=-I$(OPENSSL_PREFIX)/include - SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto -endif - -ifeq ($(uname_S),SunOS) - IS_SUN_CC=$(shell sh -c '$(CC) -V 2>&1 |egrep -i -c "sun|studio"') - ifeq ($(IS_SUN_CC),1) - SUN_SHARED_FLAG=-G - else - SUN_SHARED_FLAG=-shared - endif - REAL_LDFLAGS+= -ldl -lnsl -lsocket - DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) - SSL_DYLIB_MAKE_CMD=$(CC) $(SUN_SHARED_FLAG) -o $(SSL_DYLIBNAME) -h $(SSL_DYLIB_MINOR_NAME) $(LDFLAGS) $(SSL_LDFLAGS) -endif -ifeq ($(uname_S),Darwin) - DYLIBSUFFIX=dylib - DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX) - DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) - SSL_DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME) -o $(SSL_DYLIBNAME) $(LDFLAGS) $(SSL_LDFLAGS) - DYLIB_PLUGIN=-Wl,-undefined -Wl,dynamic_lookup -endif - -all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) -ifeq ($(USE_SSL),1) -all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME) -endif - -# Deps (use make dep to generate this) -alloc.o: alloc.c fmacros.h alloc.h -async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h -dict.o: dict.c fmacros.h alloc.h dict.h -hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h -read.o: read.c fmacros.h alloc.h read.h sds.h win32.h -sds.o: sds.c sds.h sdsalloc.h alloc.h -sockcompat.o: sockcompat.c sockcompat.h -ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h -test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h sockcompat.h win32.h - -$(DYLIBNAME): $(OBJ) - $(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS) - -$(STLIBNAME): $(OBJ) - $(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ) - -$(SSL_DYLIBNAME): $(SSL_OBJ) - $(SSL_DYLIB_MAKE_CMD) $(DYLIB_PLUGIN) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(LDFLAGS) $(SSL_LDFLAGS) - -$(SSL_STLIBNAME): $(SSL_OBJ) - $(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ) - -dynamic: $(DYLIBNAME) -static: $(STLIBNAME) -ifeq ($(USE_SSL),1) -dynamic: $(SSL_DYLIBNAME) -static: $(SSL_STLIBNAME) -endif - -# Binaries: -hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS) - -hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS) - - -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) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS) -endif - -ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),) -hiredis-example-qt: - @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR" - @false -else -hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) - $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ - $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore - $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ - $(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore - $(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore -endif - -hiredis-example: examples/example.c $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) - -hiredis-example-push: examples/example-push.c $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) - -examples: $(EXAMPLES) - -TEST_LIBS = $(STLIBNAME) -ifeq ($(USE_SSL),1) - TEST_LIBS += $(SSL_STLIBNAME) - TEST_LDFLAGS = $(SSL_LDFLAGS) -lssl -lcrypto -lpthread -endif - -hiredis-test: test.o $(TEST_LIBS) - $(CC) -o $@ $(REAL_CFLAGS) -I. $^ $(REAL_LDFLAGS) $(TEST_LDFLAGS) - -hiredis-%: %.o $(STLIBNAME) - $(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS) - -test: hiredis-test - ./hiredis-test - -check: hiredis-test - TEST_SSL=$(USE_SSL) ./test.sh - -.c.o: - $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< - -clean: - rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov - -dep: - $(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c - -INSTALL?= cp -pPR - -$(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_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ - @echo Libs: -L\$${libdir} -lhiredis >> $@ - @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ - -$(SSL_PKGCONFNAME): hiredis_ssl.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_ssl >> $@ - @echo Description: SSL Support for hiredis. >> $@ - @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ - @echo Requires: hiredis >> $@ - @echo Libs: -L\$${libdir} -lhiredis_ssl >> $@ - @echo Libs.private: -lssl -lcrypto >> $@ - -install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) - mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH) - $(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters - $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) - $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) - mkdir -p $(INSTALL_PKGCONF_PATH) - $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) - -ifeq ($(USE_SSL),1) -install: install-ssl - -install-ssl: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME) - mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis_ssl.h $(INSTALL_INCLUDE_PATH) - $(INSTALL) $(SSL_DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(SSL_DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(SSL_DYLIB_MINOR_NAME) $(SSL_DYLIBNAME) - $(INSTALL) $(SSL_STLIBNAME) $(INSTALL_LIBRARY_PATH) - mkdir -p $(INSTALL_PKGCONF_PATH) - $(INSTALL) $(SSL_PKGCONFNAME) $(INSTALL_PKGCONF_PATH) -endif - -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 32bit-vars gprof gcov noopt diff --git a/ext/hiredis-1.0.2/README.md b/ext/hiredis-1.0.2/README.md deleted file mode 100644 index c544d571..00000000 --- a/ext/hiredis-1.0.2/README.md +++ /dev/null @@ -1,664 +0,0 @@ -[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis) - -**This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline&l=hiredis)).** - -# HIREDIS - -Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database. - -It is minimalistic because it just adds minimal support for the protocol, but -at the same time it uses a high level printf-alike API in order to make it -much higher level than otherwise suggested by its minimal code base and the -lack of explicit bindings for every Redis command. - -Apart from supporting sending commands and receiving replies, it comes with -a reply parser that is decoupled from the I/O layer. It -is a stream parser designed for easy reusability, which can for instance be used -in higher level language bindings for efficient reply parsing. - -Hiredis only supports the binary-safe Redis protocol, so you can use it with any -Redis version >= 1.2.0. - -The library comes with multiple APIs. There is the -*synchronous API*, the *asynchronous API* and the *reply parsing API*. - -## Upgrading to `1.0.2` - -NOTE: v1.0.1 erroneously bumped SONAME, which is why it is skipped here. - -Version 1.0.2 is simply 1.0.0 with a fix for [CVE-2021-32765](https://github.com/redis/hiredis/security/advisories/GHSA-hfm9-39pp-55p2). They are otherwise identical. - -## Upgrading to `1.0.0` - -Version 1.0.0 marks the first stable release of Hiredis. -It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory. -It also bundles the updated `sds` library, to sync up with upstream and Redis. -For code changes see the [Changelog](CHANGELOG.md). - -_Note: As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._ - -## IMPORTANT: Breaking changes from `0.14.1` -> `1.0.0` - -* `redisContext` has two additional members (`free_privdata`, and `privctx`). -* `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`. -* `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter. - -## IMPORTANT: Breaking changes when upgrading from 0.13.x -> 0.14.x - -Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now -protocol errors. This is consistent with the RESP specification. On 32-bit -platforms, the upper bound is lowered to `SIZE_MAX`. - -Change `redisReply.len` to `size_t`, as it denotes the the size of a string - -User code should compare this to `size_t` values as well. If it was used to -compare to other values, casting might be necessary or can be removed, if -casting was applied before. - -## Upgrading from `<0.9.0` - -Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing -code using hiredis should not be a big pain. The key thing to keep in mind when -upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to -the stateless 0.0.1 that only has a file descriptor to work with. - -## Synchronous API - -To consume the synchronous API, there are only a few function calls that need to be introduced: - -```c -redisContext *redisConnect(const char *ip, int port); -void *redisCommand(redisContext *c, const char *format, ...); -void freeReplyObject(void *reply); -``` - -### Connecting - -The function `redisConnect` is used to create a so-called `redisContext`. The -context is where Hiredis holds state for a connection. The `redisContext` -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. More information on errors can be found in the **Errors** section. -After trying to connect to Redis using `redisConnect` you should -check the `err` field to see if establishing the connection was successful: -```c -redisContext *c = redisConnect("127.0.0.1", 6379); -if (c == NULL || c->err) { - if (c) { - printf("Error: %s\n", c->errstr); - // handle error - } else { - printf("Can't allocate redis context\n"); - } -} -``` - -*Note: A `redisContext` is not thread-safe.* - -### Sending commands - -There are several ways to issue commands to Redis. The first that will be introduced is -`redisCommand`. This function takes a format similar to printf. In the simplest form, -it is used like this: -```c -reply = redisCommand(context, "SET foo bar"); -``` - -The specifier `%s` interpolates a string in the command, and uses `strlen` to -determine the length of the string: -```c -reply = redisCommand(context, "SET foo %s", value); -``` -When you need to pass binary safe strings in a command, the `%b` specifier can be -used. Together with a pointer to the string, it requires a `size_t` length argument -of the string: -```c -reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen); -``` -Internally, Hiredis 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 = redisCommand(context, "SET key:%s %s", myid, value); -``` - -### Using replies - -The return value of `redisCommand` holds a reply when the command was -successfully executed. When an error occurs, the return value is `NULL` and -the `err` field in the context will be set (see section on **Errors**). -Once an error is returned the context cannot be reused and you should set up -a new connection. - -The standard replies that `redisCommand` are of the type `redisReply`. The -`type` field in the `redisReply` should be used to test what kind of reply -was received: - -### RESP2 - -* **`REDIS_REPLY_STATUS`**: - * The command replied with a status reply. The status string can be accessed using `reply->str`. - The length of this string can be accessed using `reply->len`. - -* **`REDIS_REPLY_ERROR`**: - * The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`. - -* **`REDIS_REPLY_INTEGER`**: - * The command replied with an integer. The integer value can be accessed using the - `reply->integer` field of type `long long`. - -* **`REDIS_REPLY_NIL`**: - * The command replied with a **nil** object. There is no data to access. - -* **`REDIS_REPLY_STRING`**: - * A bulk (string) reply. The value of the reply can be accessed using `reply->str`. - The length of this string can be accessed using `reply->len`. - -* **`REDIS_REPLY_ARRAY`**: - * A multi bulk reply. The number of elements in the multi bulk reply is stored in - `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well - and can be accessed via `reply->element[..index..]`. - Redis may reply with nested arrays but this is fully supported. - -### RESP3 - -Hiredis also supports every new `RESP3` data type which are as follows. For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md) - -* **`REDIS_REPLY_DOUBLE`**: - * The command replied with a double-precision floating point number. - The value is stored as a string in the `str` member, and can be converted with `strtod` or similar. - -* **`REDIS_REPLY_BOOL`**: - * A boolean true/false reply. - The value is stored in the `integer` member and will be either `0` or `1`. - -* **`REDIS_REPLY_MAP`**: - * An array with the added invariant that there will always be an even number of elements. - The MAP is functionally equivelant to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant. - -* **`REDIS_REPLY_SET`**: - * An array response where each entry is unique. - Like the MAP type, the data is identical to an array response except there are no duplicate values. - -* **`REDIS_REPLY_PUSH`**: - * An array that can be generated spontaneously by Redis. - This array response will always contain at least two subelements. The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself. - -* **`REDIS_REPLY_ATTR`**: - * An array structurally identical to a `MAP` but intended as meta-data about a reply. - _As of Redis 6.0.6 this reply type is not used in Redis_ - -* **`REDIS_REPLY_BIGNUM`**: - * A string representing an arbitrarily large signed or unsigned integer value. - The number will be encoded as a string in the `str` member of `redisReply`. - -* **`REDIS_REPLY_VERB`**: - * A verbatim string, intended to be presented to the user without modification. - The string payload is stored in the `str` memeber, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown). - -Replies should be freed using the `freeReplyObject()` function. -Note that this function will take care of freeing sub-reply objects -contained in arrays and nested arrays, so there is no need for the user to -free the sub replies (it is actually harmful and will corrupt the memory). - -**Important:** the current version of hiredis (1.0.0) frees replies when the -asynchronous API is used. This means you should not call `freeReplyObject` when -you use this API. The reply is cleaned up by hiredis _after_ the callback -returns. We may introduce a flag to make this configurable in future versions of the library. - -### Cleaning up - -To disconnect and free the context the following function can be used: -```c -void redisFree(redisContext *c); -``` -This function immediately closes the socket and then frees the allocations done in -creating the context. - -### Sending commands (cont'd) - -Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands. -It has the following prototype: -```c -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); -``` -It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the -arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will -use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments -need to be binary safe, the entire array of lengths `argvlen` should be provided. - -The return value has the same semantic as `redisCommand`. - -### Pipelining - -To explain how Hiredis supports pipelining in a blocking connection, there needs to be -understanding of the internal execution flow. - -When any of the functions in the `redisCommand` family is called, Hiredis first formats the -command according to the Redis protocol. The formatted command is then put in the output buffer -of the context. This output buffer is dynamic, so it can hold any number of commands. -After the command is put in the output buffer, `redisGetReply` is called. This function has the -following two execution paths: - -1. The input buffer is non-empty: - * Try to parse a single reply from the input buffer and return it - * If no reply could be parsed, continue at *2* -2. The input buffer is empty: - * Write the **entire** output buffer to the socket - * Read from the socket until a single reply could be parsed - -The function `redisGetReply` 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 `redisCommand` family, apart from not returning a reply: -```c -void redisAppendCommand(redisContext *c, const char *format, ...); -void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); -``` -After calling either function one or more times, `redisGetReply` 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. - -The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and -a single call to `read(2)`): -```c -redisReply *reply; -redisAppendCommand(context,"SET foo bar"); -redisAppendCommand(context,"GET foo"); -redisGetReply(context,(void *)&reply); // reply for SET -freeReplyObject(reply); -redisGetReply(context,(void *)&reply); // reply for GET -freeReplyObject(reply); -``` -This API can also be used to implement a blocking subscriber: -```c -reply = redisCommand(context,"SUBSCRIBE foo"); -freeReplyObject(reply); -while(redisGetReply(context,(void *)&reply) == REDIS_OK) { - // consume message - freeReplyObject(reply); -} -``` -### Errors - -When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is -returned. The `err` field inside the context will be non-zero and set to one of the -following constants: - -* **`REDIS_ERR_IO`**: - There was an I/O error while creating the connection, trying to write - to the socket or read from the socket. If you included `errno.h` in your - application, you can use the global `errno` variable to find out what is - wrong. - -* **`REDIS_ERR_EOF`**: - The server closed the connection which resulted in an empty read. - -* **`REDIS_ERR_PROTOCOL`**: - There was an error while parsing the protocol. - -* **`REDIS_ERR_OTHER`**: - Any other error. Currently, it is only used when a specified hostname to connect - to cannot be resolved. - -In every case, the `errstr` field in the context will be set to hold a string representation -of the error. - -## Asynchronous API - -Hiredis comes with an asynchronous API that works easily with any event library. -Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html) -and [libevent](http://monkey.org/~provos/libevent/). - -### 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. - -*Note: A `redisAsyncContext` is not thread-safe.* - -```c -redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); -if (c->err) { - printf("Error: %s\n", c->errstr); - // handle error -} -``` - -The 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. - -The context object is always freed after the disconnect callback fired. When a reconnect is needed, -the disconnect callback is a good point to do so. - -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 redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); -``` -`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback. -### Sending commands and their callbacks - -In an asynchronous context, commands are automatically pipelined due to the nature of an event loop. -Therefore, unlike the synchronous API, there is only a single way to send commands. -Because commands are sent to Redis 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(redisAsyncContext *c, 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 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); -``` -Both functions 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 `redisAsyncCommand` 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 asynchronous connection can be terminated using: -```c -void redisAsyncDisconnect(redisAsyncContext *ac); -``` -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 context object after it is created. -See the `adapters/` directory for bindings to *libev* and *libevent*. - -## Reply parsing API - -Hiredis comes with a reply parsing API that makes it easy for writing higher -level language bindings. - -The reply parsing API consists of the following functions: -```c -redisReader *redisReaderCreate(void); -void redisReaderFree(redisReader *reader); -int redisReaderFeed(redisReader *reader, const char *buf, size_t len); -int redisReaderGetReply(redisReader *reader, void **reply); -``` -The same set of functions are used internally by hiredis when creating a -normal Redis context, the above API just exposes it to the user for a direct -usage. - -### Usage - -The function `redisReaderCreate` creates a `redisReader` structure that holds a -buffer with unparsed data and state for the protocol parser. - -Incoming data -- most likely from a socket -- can be placed in the internal -buffer of the `redisReader` using `redisReaderFeed`. This function will make a -copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed -when `redisReaderGetReply` is called. This function returns an integer status -and a reply object (as described above) via `void **reply`. The returned status -can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went -wrong (either a protocol error, or an out of memory error). - -The parser limits the level of nesting for multi bulk payloads to 7. If the -multi bulk nesting level is higher than this, the parser returns an error. - -### Customizing replies - -The function `redisReaderGetReply` creates `redisReply` and makes the function -argument `reply` point to the created `redisReply` variable. For instance, if -the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply` -will hold the status as a vanilla C string. However, the functions that are -responsible for creating instances of the `redisReply` can be customized by -setting the `fn` field on the `redisReader` struct. This should be done -immediately after creating the `redisReader`. - -For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c) -uses customized reply object functions to create Ruby objects. - -### Reader max buffer - -Both when using the Reader API directly or when using it indirectly via a -normal Redis context, the redisReader structure uses a buffer in order to -accumulate data from the server. -Usually this buffer is destroyed when it is empty and is larger than 16 -KiB in order to avoid wasting memory in unused buffers - -However when working with very big payloads destroying the buffer may slow -down performances considerably, so it is possible to modify the max size of -an idle buffer changing the value of the `maxbuf` field of the reader structure -to the desired value. The special value of 0 means that there is no maximum -value for an idle buffer, so the buffer will never get freed. - -For instance if you have a normal Redis context you can set the maximum idle -buffer to zero (unlimited) just with: -```c -context->reader->maxbuf = 0; -``` -This should be done only in order to maximize performances when working with -large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again -as soon as possible in order to prevent allocation of useless memory. - -### Reader max array elements - -By default the hiredis reply parser sets the maximum number of multi-bulk elements -to 2^32 - 1 or 4,294,967,295 entries. If you need to process multi-bulk replies -with more than this many elements you can set the value higher or to zero, meaning -unlimited with: -```c -context->reader->maxelements = 0; -``` - -## SSL/TLS Support - -### Building - -SSL/TLS support is not built by default and requires an explicit flag: - - make USE_SSL=1 - -This requires OpenSSL development package (e.g. including header files to be -available. - -When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and -`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries -unaffected so no additional dependencies are introduced. - -### Using it - -First, you'll need to make sure you include the SSL header file: - -```c -#include "hiredis.h" -#include "hiredis_ssl.h" -``` - -You will also need to link against `libhiredis_ssl`, **in addition** to -`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies. - -Hiredis implements SSL/TLS on top of its normal `redisContext` or -`redisAsyncContext`, so you will need to establish a connection first and then -initiate an SSL/TLS handshake. - -#### Hiredis OpenSSL Wrappers - -Before Hiredis can negotiate an SSL/TLS connection, it is necessary to -initialize OpenSSL and create a context. You can do that in two ways: - -1. Work directly with the OpenSSL API to initialize the library's global context - and create `SSL_CTX *` and `SSL *` contexts. With an `SSL *` object you can - call `redisInitiateSSL()`. -2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a - `redisSSLContext` object to hold configuration and use - `redisInitiateSSLWithContext()` to initiate the SSL/TLS handshake. - -```c -/* An Hiredis SSL context. It holds SSL configuration and can be reused across - * many contexts. - */ -redisSSLContext *ssl; - -/* An error variable to indicate what went wrong, if the context fails to - * initialize. - */ -redisSSLContextError ssl_error; - -/* Initialize global OpenSSL state. - * - * You should call this only once when your app initializes, and only if - * you don't explicitly or implicitly initialize OpenSSL it elsewhere. - */ -redisInitOpenSSL(); - -/* Create SSL context */ -ssl = redisCreateSSLContext( - "cacertbundle.crt", /* File name of trusted CA/ca bundle file, optional */ - "/path/to/certs", /* Path of trusted certificates, optional */ - "client_cert.pem", /* File name of client certificate file, optional */ - "client_key.pem", /* File name of client private key, optional */ - "redis.mydomain.com", /* Server name to request (SNI), optional */ - &ssl_error - ) != REDIS_OK) { - printf("SSL error: %s\n", redisSSLContextGetError(ssl_error); - /* Abort... */ - } - -/* Create Redis context and establish connection */ -c = redisConnect("localhost", 6443); -if (c == NULL || c->err) { - /* Handle error and abort... */ -} - -/* Negotiate SSL/TLS */ -if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) { - /* Handle error, in c->err / c->errstr */ -} -``` - -## RESP3 PUSH replies -Redis 6.0 introduced PUSH replies with the reply-type `>`. These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks. - -### Default behavior -Hiredis installs handlers on `redisContext` and `redisAsyncContext` by default, which will intercept and free any PUSH replies detected. This means existing code will work as-is after upgrading to Redis 6 and switching to `RESP3`. - -### Custom PUSH handler prototypes -The callback prototypes differ between `redisContext` and `redisAsyncContext`. - -#### redisContext -```c -void my_push_handler(void *privdata, void *reply) { - /* Handle the reply */ - - /* Note: We need to free the reply in our custom handler for - blocking contexts. This lets us keep the reply if - we want. */ - freeReplyObject(reply); -} -``` - -#### redisAsyncContext -```c -void my_async_push_handler(redisAsyncContext *ac, void *reply) { - /* Handle the reply */ - - /* Note: Because async hiredis always frees replies, you should - not call freeReplyObject in an async push callback. */ -} -``` - -### Installing a custom handler -There are two ways to set your own PUSH handlers. - -1. Set `push_cb` or `async_push_cb` in the `redisOptions` struct and connect with `redisConnectWithOptions` or `redisAsyncConnectWithOptions`. - ```c - redisOptions = {0}; - REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379); - options->push_cb = my_push_handler; - redisContext *context = redisConnectWithOptions(&options); - ``` -2. Call `redisSetPushCallback` or `redisAsyncSetPushCallback` on a connected context. - ```c - redisContext *context = redisConnect("127.0.0.1", 6379); - redisSetPushCallback(context, my_push_handler); - ``` - - _Note `redisSetPushCallback` and `redisAsyncSetPushCallback` both return any currently configured handler, making it easy to override and then return to the old value._ - -### Specifying no handler -If you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all. This can be done in two ways. -1. Set the `REDIS_OPT_NO_PUSH_AUTOFREE` flag in `redisOptions` and leave the callback function pointer `NULL`. - ```c - redisOptions = {0}; - REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379); - options->options |= REDIS_OPT_NO_PUSH_AUTOFREE; - redisContext *context = redisConnectWithOptions(&options); - ``` -3. Call `redisSetPushCallback` with `NULL` once connected. - ```c - redisContext *context = redisConnect("127.0.0.1", 6379); - redisSetPushCallback(context, NULL); - ``` - - _Note: With no handler configured, calls to `redisCommand` may generate more than one reply, so this strategy is only applicable when there's some kind of blocking`redisGetReply()` loop (e.g. `MONITOR` or `SUBSCRIBE` workloads)._ - -## Allocator injection - -Hiredis uses a pass-thru structure of function pointers defined in [alloc.h](https://github.com/redis/hiredis/blob/f5d25850/alloc.h#L41) that contain the currently configured allocation and deallocation functions. By default they just point to libc (`malloc`, `calloc`, `realloc`, etc). - -### Overriding - -One can override the allocators like so: - -```c -hiredisAllocFuncs myfuncs = { - .mallocFn = my_malloc, - .callocFn = my_calloc, - .reallocFn = my_realloc, - .strdupFn = my_strdup, - .freeFn = my_free, -}; - -// Override allocators (function returns current allocators if needed) -hiredisAllocFuncs orig = hiredisSetAllocators(&myfuncs); -``` - -To reset the allocators to their default libc function simply call: - -```c -hiredisResetAllocators(); -``` - -## AUTHORS - -Salvatore Sanfilippo (antirez at gmail),\ -Pieter Noordhuis (pcnoordhuis at gmail)\ -Michael Grunder (michael dot grunder at gmail) - -_Hiredis is released under the BSD license._ diff --git a/ext/hiredis-1.0.2/adapters/ae.h b/ext/hiredis-1.0.2/adapters/ae.h deleted file mode 100644 index 660d82eb..00000000 --- a/ext/hiredis-1.0.2/adapters/ae.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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" - -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); - hi_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*)hi_malloc(sizeof(*e)); - if (e == NULL) - return REDIS_ERR; - - 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; -} -#endif diff --git a/ext/hiredis-1.0.2/adapters/glib.h b/ext/hiredis-1.0.2/adapters/glib.h deleted file mode 100644 index ad59dd14..00000000 --- a/ext/hiredis-1.0.2/adapters/glib.h +++ /dev/null @@ -1,156 +0,0 @@ -#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 = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_IN; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_del_read (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_IN; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_add_write (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_OUT; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_del_write (gpointer data) -{ - RedisSource *source = (RedisSource *)data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_OUT; - g_main_context_wakeup(g_source_get_context((GSource *)data)); -} - -static void -redis_source_cleanup (gpointer data) -{ - RedisSource *source = (RedisSource *)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((GSource *)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); - if (source == NULL) - return NULL; - - 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-1.0.2/adapters/ivykis.h b/ext/hiredis-1.0.2/adapters/ivykis.h deleted file mode 100644 index 179f6ab5..00000000 --- a/ext/hiredis-1.0.2/adapters/ivykis.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __HIREDIS_IVYKIS_H__ -#define __HIREDIS_IVYKIS_H__ -#include -#include "../hiredis.h" -#include "../async.h" - -typedef struct redisIvykisEvents { - redisAsyncContext *context; - struct iv_fd fd; -} redisIvykisEvents; - -static void redisIvykisReadEvent(void *arg) { - redisAsyncContext *context = (redisAsyncContext *)arg; - redisAsyncHandleRead(context); -} - -static void redisIvykisWriteEvent(void *arg) { - redisAsyncContext *context = (redisAsyncContext *)arg; - redisAsyncHandleWrite(context); -} - -static void redisIvykisAddRead(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent); -} - -static void redisIvykisDelRead(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_in(&e->fd, NULL); -} - -static void redisIvykisAddWrite(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent); -} - -static void redisIvykisDelWrite(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - iv_fd_set_handler_out(&e->fd, NULL); -} - -static void redisIvykisCleanup(void *privdata) { - redisIvykisEvents *e = (redisIvykisEvents*)privdata; - - iv_fd_unregister(&e->fd); - hi_free(e); -} - -static int redisIvykisAttach(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisIvykisEvents *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 = (redisIvykisEvents*)hi_malloc(sizeof(*e)); - if (e == NULL) - return REDIS_ERR; - - e->context = ac; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisIvykisAddRead; - ac->ev.delRead = redisIvykisDelRead; - ac->ev.addWrite = redisIvykisAddWrite; - ac->ev.delWrite = redisIvykisDelWrite; - ac->ev.cleanup = redisIvykisCleanup; - ac->ev.data = e; - - /* Initialize and install read/write events */ - IV_FD_INIT(&e->fd); - e->fd.fd = c->fd; - e->fd.handler_in = redisIvykisReadEvent; - e->fd.handler_out = redisIvykisWriteEvent; - e->fd.handler_err = NULL; - e->fd.cookie = e->context; - - iv_fd_register(&e->fd); - - return REDIS_OK; -} -#endif diff --git a/ext/hiredis-1.0.2/adapters/libev.h b/ext/hiredis-1.0.2/adapters/libev.h deleted file mode 100644 index e1e7bbd9..00000000 --- a/ext/hiredis-1.0.2/adapters/libev.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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; - ev_timer timer; -} 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 redisLibevStopTimer(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - ev_timer_stop(EV_A_ &e->timer); -} - -static void redisLibevCleanup(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - redisLibevDelRead(privdata); - redisLibevDelWrite(privdata); - redisLibevStopTimer(privdata); - hi_free(e); -} - -static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) { - ((void)revents); - redisLibevEvents *e = (redisLibevEvents*)timer->data; - redisAsyncHandleTimeout(e->context); -} - -static void redisLibevSetTimeout(void *privdata, struct timeval tv) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - - if (!ev_is_active(&e->timer)) { - ev_init(&e->timer, redisLibevTimeout); - e->timer.data = e; - } - - e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00; - ev_timer_again(EV_A_ &e->timer); -} - -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*)hi_calloc(1, sizeof(*e)); - if (e == NULL) - return REDIS_ERR; - - e->context = ac; -#if EV_MULTIPLICITY - e->loop = loop; -#else - e->loop = NULL; -#endif - 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.scheduleTimer = redisLibevSetTimeout; - 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-1.0.2/adapters/libevent.h b/ext/hiredis-1.0.2/adapters/libevent.h deleted file mode 100644 index 9150979b..00000000 --- a/ext/hiredis-1.0.2/adapters/libevent.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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" - -#define REDIS_LIBEVENT_DELETED 0x01 -#define REDIS_LIBEVENT_ENTERED 0x02 - -typedef struct redisLibeventEvents { - redisAsyncContext *context; - struct event *ev; - struct event_base *base; - struct timeval tv; - short flags; - short state; -} redisLibeventEvents; - -static void redisLibeventDestroy(redisLibeventEvents *e) { - hi_free(e); -} - -static void redisLibeventHandler(int fd, short event, void *arg) { - ((void)fd); - redisLibeventEvents *e = (redisLibeventEvents*)arg; - e->state |= REDIS_LIBEVENT_ENTERED; - - #define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\ - redisLibeventDestroy(e);\ - return; \ - } - - if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) { - redisAsyncHandleTimeout(e->context); - CHECK_DELETED(); - } - - if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { - redisAsyncHandleRead(e->context); - CHECK_DELETED(); - } - - if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { - redisAsyncHandleWrite(e->context); - CHECK_DELETED(); - } - - e->state &= ~REDIS_LIBEVENT_ENTERED; - #undef CHECK_DELETED -} - -static void redisLibeventUpdate(void *privdata, short flag, int isRemove) { - redisLibeventEvents *e = (redisLibeventEvents *)privdata; - const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL; - - if (isRemove) { - if ((e->flags & flag) == 0) { - return; - } else { - e->flags &= ~flag; - } - } else { - if (e->flags & flag) { - return; - } else { - e->flags |= flag; - } - } - - event_del(e->ev); - event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST, - redisLibeventHandler, privdata); - event_add(e->ev, tv); -} - -static void redisLibeventAddRead(void *privdata) { - redisLibeventUpdate(privdata, EV_READ, 0); -} - -static void redisLibeventDelRead(void *privdata) { - redisLibeventUpdate(privdata, EV_READ, 1); -} - -static void redisLibeventAddWrite(void *privdata) { - redisLibeventUpdate(privdata, EV_WRITE, 0); -} - -static void redisLibeventDelWrite(void *privdata) { - redisLibeventUpdate(privdata, EV_WRITE, 1); -} - -static void redisLibeventCleanup(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - if (!e) { - return; - } - event_del(e->ev); - event_free(e->ev); - e->ev = NULL; - - if (e->state & REDIS_LIBEVENT_ENTERED) { - e->state |= REDIS_LIBEVENT_DELETED; - } else { - redisLibeventDestroy(e); - } -} - -static void redisLibeventSetTimeout(void *privdata, struct timeval tv) { - redisLibeventEvents *e = (redisLibeventEvents *)privdata; - short flags = e->flags; - e->flags = 0; - e->tv = tv; - redisLibeventUpdate(e, flags, 0); -} - -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*)hi_calloc(1, sizeof(*e)); - if (e == NULL) - return REDIS_ERR; - - 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.scheduleTimer = redisLibeventSetTimeout; - ac->ev.data = e; - - /* Initialize and install read/write events */ - e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e); - e->base = base; - return REDIS_OK; -} -#endif diff --git a/ext/hiredis-1.0.2/adapters/libuv.h b/ext/hiredis-1.0.2/adapters/libuv.h deleted file mode 100644 index c120b1b3..00000000 --- a/ext/hiredis-1.0.2/adapters/libuv.h +++ /dev/null @@ -1,117 +0,0 @@ -#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; - int ev = (status ? p->events : events); - - if (p->context != NULL && (ev & UV_READABLE)) { - redisAsyncHandleRead(p->context); - } - if (p->context != NULL && (ev & 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; - - hi_free(p); -} - - -static void redisLibuvCleanup(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->context = NULL; // indicate that context might no longer exist - 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*)hi_malloc(sizeof(*p)); - if (p == NULL) - return REDIS_ERR; - - memset(p, 0, sizeof(*p)); - - if (uv_poll_init_socket(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-1.0.2/adapters/macosx.h b/ext/hiredis-1.0.2/adapters/macosx.h deleted file mode 100644 index 3c87f1b2..00000000 --- a/ext/hiredis-1.0.2/adapters/macosx.h +++ /dev/null @@ -1,115 +0,0 @@ -// -// Created by Дмитрий Бахвалов on 13.07.15. -// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. -// - -#ifndef __HIREDIS_MACOSX_H__ -#define __HIREDIS_MACOSX_H__ - -#include - -#include "../hiredis.h" -#include "../async.h" - -typedef struct { - redisAsyncContext *context; - CFSocketRef socketRef; - CFRunLoopSourceRef sourceRef; -} RedisRunLoop; - -static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { - if( redisRunLoop != NULL ) { - if( redisRunLoop->sourceRef != NULL ) { - CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); - CFRelease(redisRunLoop->sourceRef); - } - if( redisRunLoop->socketRef != NULL ) { - CFSocketInvalidate(redisRunLoop->socketRef); - CFRelease(redisRunLoop->socketRef); - } - hi_free(redisRunLoop); - } - return REDIS_ERR; -} - -static void redisMacOSAddRead(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); -} - -static void redisMacOSDelRead(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); -} - -static void redisMacOSAddWrite(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); -} - -static void redisMacOSDelWrite(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); -} - -static void redisMacOSCleanup(void *privdata) { - RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; - freeRedisRunLoop(redisRunLoop); -} - -static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { - redisAsyncContext* context = (redisAsyncContext*) info; - - switch (callbackType) { - case kCFSocketReadCallBack: - redisAsyncHandleRead(context); - break; - - case kCFSocketWriteCallBack: - redisAsyncHandleWrite(context); - break; - - default: - break; - } -} - -static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { - redisContext *redisCtx = &(redisAsyncCtx->c); - - /* Nothing should be attached when something is already attached */ - if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; - - RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop)); - if (redisRunLoop == NULL) - return REDIS_ERR; - - /* Setup redis stuff */ - redisRunLoop->context = redisAsyncCtx; - - redisAsyncCtx->ev.addRead = redisMacOSAddRead; - redisAsyncCtx->ev.delRead = redisMacOSDelRead; - redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; - redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; - redisAsyncCtx->ev.cleanup = redisMacOSCleanup; - redisAsyncCtx->ev.data = redisRunLoop; - - /* Initialize and install read/write events */ - CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; - - redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, - kCFSocketReadCallBack | kCFSocketWriteCallBack, - redisMacOSAsyncCallback, - &socketCtx); - if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); - - redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); - if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); - - CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); - - return REDIS_OK; -} - -#endif - diff --git a/ext/hiredis-1.0.2/adapters/qt.h b/ext/hiredis-1.0.2/adapters/qt.h deleted file mode 100644 index 5cc02e6c..00000000 --- a/ext/hiredis-1.0.2/adapters/qt.h +++ /dev/null @@ -1,135 +0,0 @@ -/*- - * Copyright (C) 2014 Pietro Cerutti - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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_QT_H__ -#define __HIREDIS_QT_H__ -#include -#include "../async.h" - -static void RedisQtAddRead(void *); -static void RedisQtDelRead(void *); -static void RedisQtAddWrite(void *); -static void RedisQtDelWrite(void *); -static void RedisQtCleanup(void *); - -class RedisQtAdapter : public QObject { - - Q_OBJECT - - friend - void RedisQtAddRead(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->addRead(); - } - - friend - void RedisQtDelRead(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->delRead(); - } - - friend - void RedisQtAddWrite(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->addWrite(); - } - - friend - void RedisQtDelWrite(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->delWrite(); - } - - friend - void RedisQtCleanup(void * adapter) { - RedisQtAdapter * a = static_cast(adapter); - a->cleanup(); - } - - public: - RedisQtAdapter(QObject * parent = 0) - : QObject(parent), m_ctx(0), m_read(0), m_write(0) { } - - ~RedisQtAdapter() { - if (m_ctx != 0) { - m_ctx->ev.data = NULL; - } - } - - int setContext(redisAsyncContext * ac) { - if (ac->ev.data != NULL) { - return REDIS_ERR; - } - m_ctx = ac; - m_ctx->ev.data = this; - m_ctx->ev.addRead = RedisQtAddRead; - m_ctx->ev.delRead = RedisQtDelRead; - m_ctx->ev.addWrite = RedisQtAddWrite; - m_ctx->ev.delWrite = RedisQtDelWrite; - m_ctx->ev.cleanup = RedisQtCleanup; - return REDIS_OK; - } - - private: - void addRead() { - if (m_read) return; - m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0); - connect(m_read, SIGNAL(activated(int)), this, SLOT(read())); - } - - void delRead() { - if (!m_read) return; - delete m_read; - m_read = 0; - } - - void addWrite() { - if (m_write) return; - m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0); - connect(m_write, SIGNAL(activated(int)), this, SLOT(write())); - } - - void delWrite() { - if (!m_write) return; - delete m_write; - m_write = 0; - } - - void cleanup() { - delRead(); - delWrite(); - } - - private slots: - void read() { redisAsyncHandleRead(m_ctx); } - void write() { redisAsyncHandleWrite(m_ctx); } - - private: - redisAsyncContext * m_ctx; - QSocketNotifier * m_read; - QSocketNotifier * m_write; -}; - -#endif /* !__HIREDIS_QT_H__ */ diff --git a/ext/hiredis-1.0.2/alloc.c b/ext/hiredis-1.0.2/alloc.c deleted file mode 100644 index 7fb6b35e..00000000 --- a/ext/hiredis-1.0.2/alloc.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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 "alloc.h" -#include -#include - -hiredisAllocFuncs hiredisAllocFns = { - .mallocFn = malloc, - .callocFn = calloc, - .reallocFn = realloc, - .strdupFn = strdup, - .freeFn = free, -}; - -/* Override hiredis' allocators with ones supplied by the user */ -hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *override) { - hiredisAllocFuncs orig = hiredisAllocFns; - - hiredisAllocFns = *override; - - return orig; -} - -/* Reset allocators to use libc defaults */ -void hiredisResetAllocators(void) { - hiredisAllocFns = (hiredisAllocFuncs) { - .mallocFn = malloc, - .callocFn = calloc, - .reallocFn = realloc, - .strdupFn = strdup, - .freeFn = free, - }; -} - -#ifdef _WIN32 - -void *hi_malloc(size_t size) { - return hiredisAllocFns.mallocFn(size); -} - -void *hi_calloc(size_t nmemb, size_t size) { - return hiredisAllocFns.callocFn(nmemb, size); -} - -void *hi_realloc(void *ptr, size_t size) { - return hiredisAllocFns.reallocFn(ptr, size); -} - -char *hi_strdup(const char *str) { - return hiredisAllocFns.strdupFn(str); -} - -void hi_free(void *ptr) { - hiredisAllocFns.freeFn(ptr); -} - -#endif diff --git a/ext/hiredis-1.0.2/alloc.h b/ext/hiredis-1.0.2/alloc.h deleted file mode 100644 index 34a05f49..00000000 --- a/ext/hiredis-1.0.2/alloc.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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_ALLOC_H -#define HIREDIS_ALLOC_H - -#include /* for size_t */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure pointing to our actually configured allocators */ -typedef struct hiredisAllocFuncs { - void *(*mallocFn)(size_t); - void *(*callocFn)(size_t,size_t); - void *(*reallocFn)(void*,size_t); - char *(*strdupFn)(const char*); - void (*freeFn)(void*); -} hiredisAllocFuncs; - -hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha); -void hiredisResetAllocators(void); - -#ifndef _WIN32 - -/* Hiredis' configured allocator function pointer struct */ -extern hiredisAllocFuncs hiredisAllocFns; - -static inline void *hi_malloc(size_t size) { - return hiredisAllocFns.mallocFn(size); -} - -static inline void *hi_calloc(size_t nmemb, size_t size) { - return hiredisAllocFns.callocFn(nmemb, size); -} - -static inline void *hi_realloc(void *ptr, size_t size) { - return hiredisAllocFns.reallocFn(ptr, size); -} - -static inline char *hi_strdup(const char *str) { - return hiredisAllocFns.strdupFn(str); -} - -static inline void hi_free(void *ptr) { - hiredisAllocFns.freeFn(ptr); -} - -#else - -void *hi_malloc(size_t size); -void *hi_calloc(size_t nmemb, size_t size); -void *hi_realloc(void *ptr, size_t size); -char *hi_strdup(const char *str); -void hi_free(void *ptr); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* HIREDIS_ALLOC_H */ diff --git a/ext/hiredis-1.0.2/appveyor.yml b/ext/hiredis-1.0.2/appveyor.yml deleted file mode 100644 index 5b43fdbe..00000000 --- a/ext/hiredis-1.0.2/appveyor.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) -environment: - matrix: - - CYG_BASH: C:\cygwin64\bin\bash - CC: gcc - - CYG_BASH: C:\cygwin\bin\bash - CC: gcc - CFLAGS: -m32 - CXXFLAGS: -m32 - LDFLAGS: -m32 - -clone_depth: 1 - -# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail -init: - - git config --global core.autocrlf input - -# Install needed build dependencies -install: - - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - -build_script: - - 'echo building...' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 - * 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 "alloc.h" -#include -#include -#ifndef _MSC_VER -#include -#endif -#include -#include -#include -#include "async.h" -#include "net.h" -#include "dict.c" -#include "sds.h" -#include "win32.h" - -#include "async_private.h" - -/* Forward declarations of hiredis.c functions */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); -void __redisSetError(redisContext *c, int type, const char *str); - -/* 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; - - dup = hi_malloc(sizeof(*dup)); - if (dup == NULL) - return NULL; - - 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); - hi_free(val); -} - -static dictType callbackDict = { - callbackHash, - NULL, - callbackValDup, - callbackKeyCompare, - callbackKeyDestructor, - callbackValDestructor -}; - -static redisAsyncContext *redisAsyncInitialize(redisContext *c) { - redisAsyncContext *ac; - dict *channels = NULL, *patterns = NULL; - - channels = dictCreate(&callbackDict,NULL); - if (channels == NULL) - goto oom; - - patterns = dictCreate(&callbackDict,NULL); - if (patterns == NULL) - goto oom; - - ac = hi_realloc(c,sizeof(redisAsyncContext)); - if (ac == NULL) - goto oom; - - 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->dataCleanup = 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->ev.scheduleTimer = 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 = channels; - ac->sub.patterns = patterns; - - return ac; -oom: - if (channels) dictRelease(channels); - if (patterns) dictRelease(patterns); - return NULL; -} - -/* 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 *redisAsyncConnectWithOptions(const redisOptions *options) { - redisOptions myOptions = *options; - redisContext *c; - redisAsyncContext *ac; - - /* Clear any erroneously set sync callback and flag that we don't want to - * use freeReplyObject by default. */ - myOptions.push_cb = NULL; - myOptions.options |= REDIS_OPT_NO_PUSH_AUTOFREE; - - myOptions.options |= REDIS_OPT_NONBLOCK; - c = redisConnectWithOptions(&myOptions); - if (c == NULL) { - return NULL; - } - - ac = redisAsyncInitialize(c); - if (ac == NULL) { - redisFree(c); - return NULL; - } - - /* Set any configured async push handler */ - redisAsyncSetPushCallback(ac, myOptions.async_push_cb); - - __redisAsyncCopyError(ac); - return ac; -} - -redisAsyncContext *redisAsyncConnect(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - return redisAsyncConnectWithOptions(&options); -} - -redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - return redisAsyncConnectWithOptions(&options); -} - -redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.options |= REDIS_OPT_REUSEADDR; - options.endpoint.tcp.source_addr = source_addr; - return redisAsyncConnectWithOptions(&options); -} - -redisAsyncContext *redisAsyncConnectUnix(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - return redisAsyncConnectWithOptions(&options); -} - -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 = hi_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)); - hi_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; - } -} - -static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) { - if (ac->push_cb != NULL) { - ac->c.flags |= REDIS_IN_CALLBACK; - ac->push_cb(ac, reply); - ac->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 with NULL reply */ - if (ac->sub.channels) { - it = dictGetIterator(ac->sub.channels); - if (it != NULL) { - while ((de = dictNext(it)) != NULL) - __redisRunCallback(ac,dictGetEntryVal(de),NULL); - dictReleaseIterator(it); - } - - dictRelease(ac->sub.channels); - } - - if (ac->sub.patterns) { - it = dictGetIterator(ac->sub.patterns); - if (it != NULL) { - 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->dataCleanup) { - ac->dataCleanup(ac->data); - } - - /* 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. */ -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. */ - int ret = __redisShiftCallback(&ac->replies,NULL); - assert(ret == REDIS_ERR); - } else { - /* Disconnection is caused by an error, make sure that pending - * callbacks cannot call new commands. */ - c->flags |= REDIS_DISCONNECTING; - } - - /* cleanup event library on disconnect. - * this is safe to call multiple times */ - _EL_CLEANUP(ac); - - /* For non-clean disconnects, __redisAsyncFree() will execute pending - * callbacks with a NULL-reply. */ - if (!(c->flags & REDIS_NO_AUTO_FREE)) { - __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; - - /** unset the auto-free flag here, because disconnect undoes this */ - c->flags &= ~REDIS_NO_AUTO_FREE; - 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; - redisCallback *cb; - 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 || reply->type == REDIS_REPLY_PUSH) { - 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); - if (sname == NULL) - goto oom; - - de = dictFind(callbacks,sname); - if (de != NULL) { - cb = dictGetEntryVal(de); - - /* If this is an subscribe reply decrease pending counter. */ - if (strcasecmp(stype+pvariant,"subscribe") == 0) { - cb->pending_subs -= 1; - } - - memcpy(dstcb,cb,sizeof(*dstcb)); - - /* If this is an unsubscribe message, remove it. */ - if (strcasecmp(stype+pvariant,"unsubscribe") == 0) { - if (cb->pending_subs == 0) - dictDelete(callbacks,sname); - - /* If this was the last unsubscribe message, revert to - * non-subscribe mode. */ - assert(reply->element[2]->type == REDIS_REPLY_INTEGER); - - /* Unset subscribed flag only when no pipelined pending subscribe. */ - if (reply->element[2]->integer == 0 - && dictSize(ac->sub.channels) == 0 - && dictSize(ac->sub.patterns) == 0) - c->flags &= ~REDIS_SUBSCRIBED; - } - } - sdsfree(sname); - } else { - /* Shift callback for invalid commands. */ - __redisShiftCallback(&ac->sub.invalid,dstcb); - } - return REDIS_OK; -oom: - __redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; -} - -#define redisIsSpontaneousPushReply(r) \ - (redisIsPushReply(r) && !redisIsSubscribeReply(r)) - -static int redisIsSubscribeReply(redisReply *reply) { - char *str; - size_t len, off; - - /* We will always have at least one string with the subscribe/message type */ - if (reply->elements < 1 || reply->element[0]->type != REDIS_REPLY_STRING || - reply->element[0]->len < sizeof("message") - 1) - { - return 0; - } - - /* Get the string/len moving past 'p' if needed */ - off = tolower(reply->element[0]->str[0]) == 'p'; - str = reply->element[0]->str + off; - len = reply->element[0]->len - off; - - return !strncasecmp(str, "subscribe", len) || - !strncasecmp(str, "message", len); - -} - -void redisProcessCallbacks(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb = {NULL, NULL, 0, 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 - && ac->replies.head == NULL) { - __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; - } - - /* Send any non-subscribe related PUSH messages to our PUSH handler - * while allowing subscribe related PUSH messages to pass through. - * This allows existing code to be backward compatible and work in - * either RESP2 or RESP3 mode. */ - if (redisIsSpontaneousPushReply(reply)) { - __redisRunPushCallback(ac, reply); - c->reader->fn->freeObject(reply); - continue; - } - - /* 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); -} - -static void __redisAsyncHandleConnectFailure(redisAsyncContext *ac) { - if (ac->onConnect) ac->onConnect(ac, REDIS_ERR); - __redisAsyncDisconnect(ac); -} - -/* Internal helper function to detect socket status the first time a read or - * write event fires. When connecting was not successful, the connect callback - * is called with a REDIS_ERR status and the context is free'd. */ -static int __redisAsyncHandleConnect(redisAsyncContext *ac) { - int completed = 0; - redisContext *c = &(ac->c); - - if (redisCheckConnectDone(c, &completed) == REDIS_ERR) { - /* Error! */ - redisCheckSocketError(c); - __redisAsyncHandleConnectFailure(ac); - return REDIS_ERR; - } else if (completed == 1) { - /* connected! */ - if (c->connection_type == REDIS_CONN_TCP && - redisSetTcpNoDelay(c) == REDIS_ERR) { - __redisAsyncHandleConnectFailure(ac); - return REDIS_ERR; - } - - if (ac->onConnect) ac->onConnect(ac, REDIS_OK); - c->flags |= REDIS_CONNECTED; - return REDIS_OK; - } else { - return REDIS_OK; - } -} - -void redisAsyncRead(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - if (redisBufferRead(c) == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - /* Always re-schedule reads */ - _EL_ADD_READ(ac); - redisProcessCallbacks(ac); - } -} - -/* 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; - } - - c->funcs->async_read(ac); -} - -void redisAsyncWrite(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - int done = 0; - - 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); - } -} - -void redisAsyncHandleWrite(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; - } - - c->funcs->async_write(ac); -} - -void redisAsyncHandleTimeout(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb; - - if ((c->flags & REDIS_CONNECTED) && ac->replies.head == NULL) { - /* Nothing to do - just an idle timeout */ - return; - } - - if (!c->err) { - __redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout"); - } - - if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) { - ac->onConnect(ac, REDIS_ERR); - } - - while (__redisShiftCallback(&ac->replies, &cb) == REDIS_OK) { - __redisRunCallback(ac, &cb, NULL); - } - - /** - * TODO: Don't automatically sever the connection, - * rather, allow to ignore responses before the queue is clear - */ - __redisAsyncDisconnect(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; - struct dict *cbdict; - dictEntry *de; - redisCallback *existcb; - 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; - cb.pending_subs = 1; - - /* 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 (sname == NULL) - goto oom; - - if (pvariant) - cbdict = ac->sub.patterns; - else - cbdict = ac->sub.channels; - - de = dictFind(cbdict,sname); - - if (de != NULL) { - existcb = dictGetEntryVal(de); - cb.pending_subs = existcb->pending_subs + 1; - } - - ret = dictReplace(cbdict,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; -oom: - __redisSetError(&(ac->c), REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; -} - -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); - hi_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); - if (len < 0) - return REDIS_ERR; - 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; -} - -redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn) { - redisAsyncPushFn *old = ac->push_cb; - ac->push_cb = fn; - return old; -} - -int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) { - if (!ac->c.command_timeout) { - ac->c.command_timeout = hi_calloc(1, sizeof(tv)); - if (ac->c.command_timeout == NULL) { - __redisSetError(&ac->c, REDIS_ERR_OOM, "Out of memory"); - __redisAsyncCopyError(ac); - return REDIS_ERR; - } - } - - if (tv.tv_sec != ac->c.command_timeout->tv_sec || - tv.tv_usec != ac->c.command_timeout->tv_usec) - { - *ac->c.command_timeout = tv; - } - - return REDIS_OK; -} diff --git a/ext/hiredis-1.0.2/async.h b/ext/hiredis-1.0.2/async.h deleted file mode 100644 index b1d2cb26..00000000 --- a/ext/hiredis-1.0.2/async.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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; - int pending_subs; - 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); -typedef void(redisTimerCallback)(void *timer, void *privdata); - -/* 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 (*dataCleanup)(void *privdata); - - /* 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); - void (*scheduleTimer)(void *privdata, struct timeval tv); - } 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; - - /* Address used for connect() */ - struct sockaddr *saddr; - size_t addrlen; - - /* Subscription callbacks */ - struct { - redisCallbackList invalid; - struct dict *channels; - struct dict *patterns; - } sub; - - /* Any configured RESP3 PUSH handler */ - redisAsyncPushFn *push_cb; -} redisAsyncContext; - -/* Functions that proxy to hiredis */ -redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options); -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); - -redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn); -int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv); -void redisAsyncDisconnect(redisAsyncContext *ac); -void redisAsyncFree(redisAsyncContext *ac); - -/* Handle read/write events */ -void redisAsyncHandleRead(redisAsyncContext *ac); -void redisAsyncHandleWrite(redisAsyncContext *ac); -void redisAsyncHandleTimeout(redisAsyncContext *ac); -void redisAsyncRead(redisAsyncContext *ac); -void redisAsyncWrite(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-1.0.2/async_private.h b/ext/hiredis-1.0.2/async_private.h deleted file mode 100644 index b9d23fff..00000000 --- a/ext/hiredis-1.0.2/async_private.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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_PRIVATE_H -#define __HIREDIS_ASYNC_PRIVATE_H - -#define _EL_ADD_READ(ctx) \ - do { \ - refreshTimeout(ctx); \ - 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 { \ - refreshTimeout(ctx); \ - 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); \ - ctx->ev.cleanup = NULL; \ - } while(0); - -static inline void refreshTimeout(redisAsyncContext *ctx) { - #define REDIS_TIMER_ISSET(tvp) \ - (tvp && ((tvp)->tv_sec || (tvp)->tv_usec)) - - #define REDIS_EL_TIMER(ac, tvp) \ - if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \ - (ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \ - } - - if (ctx->c.flags & REDIS_CONNECTED) { - REDIS_EL_TIMER(ctx, ctx->c.command_timeout); - } else { - REDIS_EL_TIMER(ctx, ctx->c.connect_timeout); - } -} - -void __redisAsyncDisconnect(redisAsyncContext *ac); -void redisProcessCallbacks(redisAsyncContext *ac); - -#endif /* __HIREDIS_ASYNC_PRIVATE_H */ diff --git a/ext/hiredis-1.0.2/dict.c b/ext/hiredis-1.0.2/dict.c deleted file mode 100644 index 34a33ead..00000000 --- a/ext/hiredis-1.0.2/dict.c +++ /dev/null @@ -1,352 +0,0 @@ -/* 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 "alloc.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 = hi_malloc(sizeof(*ht)); - if (ht == NULL) - return NULL; - - _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 = hi_calloc(realsize,sizeof(dictEntry*)); - if (n.table == NULL) - return DICT_ERR; - - /* 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); - hi_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 = hi_malloc(sizeof(*entry)); - if (entry == NULL) - return DICT_ERR; - - 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 succeed. */ - if (dictAdd(ht, key, val) == DICT_OK) - return 1; - /* It already exists, get the entry */ - entry = dictFind(ht, key); - if (entry == NULL) - return 0; - - /* 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); - hi_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); - hi_free(he); - ht->used--; - he = nextHe; - } - } - /* Free the table and the allocated cache structure */ - hi_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); - hi_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 = hi_malloc(sizeof(*iter)); - if (iter == NULL) - return NULL; - - 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) { - hi_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 initial size, - * if the table is "full" double 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-1.0.2/dict.h b/ext/hiredis-1.0.2/dict.h deleted file mode 100644 index 95fcd280..00000000 --- a/ext/hiredis-1.0.2/dict.h +++ /dev/null @@ -1,126 +0,0 @@ -/* 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-1.0.2/examples/CMakeLists.txt b/ext/hiredis-1.0.2/examples/CMakeLists.txt deleted file mode 100644 index 1d5bc56e..00000000 --- a/ext/hiredis-1.0.2/examples/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -INCLUDE(FindPkgConfig) -# Check for GLib - -PKG_CHECK_MODULES(GLIB2 glib-2.0) -if (GLIB2_FOUND) - INCLUDE_DIRECTORIES(${GLIB2_INCLUDE_DIRS}) - LINK_DIRECTORIES(${GLIB2_LIBRARY_DIRS}) - ADD_EXECUTABLE(example-glib example-glib.c) - TARGET_LINK_LIBRARIES(example-glib hiredis ${GLIB2_LIBRARIES}) -ENDIF(GLIB2_FOUND) - -FIND_PATH(LIBEV ev.h - HINTS /usr/local /usr/opt/local - ENV LIBEV_INCLUDE_DIR) - -if (LIBEV) - # Just compile and link with libev - ADD_EXECUTABLE(example-libev example-libev.c) - TARGET_LINK_LIBRARIES(example-libev hiredis ev) -ENDIF() - -FIND_PATH(LIBEVENT event.h) -if (LIBEVENT) - ADD_EXECUTABLE(example-libevent example-libevent) - TARGET_LINK_LIBRARIES(example-libevent hiredis event) -ENDIF() - -FIND_PATH(LIBUV uv.h) -IF (LIBUV) - ADD_EXECUTABLE(example-libuv example-libuv.c) - TARGET_LINK_LIBRARIES(example-libuv hiredis uv) -ENDIF() - -IF (APPLE) - FIND_LIBRARY(CF CoreFoundation) - ADD_EXECUTABLE(example-macosx example-macosx.c) - TARGET_LINK_LIBRARIES(example-macosx hiredis ${CF}) -ENDIF() - -IF (ENABLE_SSL) - ADD_EXECUTABLE(example-ssl example-ssl.c) - TARGET_LINK_LIBRARIES(example-ssl hiredis hiredis_ssl) -ENDIF() - -ADD_EXECUTABLE(example example.c) -TARGET_LINK_LIBRARIES(example hiredis) - -ADD_EXECUTABLE(example-push example-push.c) -TARGET_LINK_LIBRARIES(example-push hiredis) diff --git a/ext/hiredis-1.0.2/examples/example-ae.c b/ext/hiredis-1.0.2/examples/example-ae.c deleted file mode 100644 index 8efa7306..00000000 --- a/ext/hiredis-1.0.2/examples/example-ae.c +++ /dev/null @@ -1,62 +0,0 @@ -#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-1.0.2/examples/example-glib.c b/ext/hiredis-1.0.2/examples/example-glib.c deleted file mode 100644 index d6e10f8e..00000000 --- a/ext/hiredis-1.0.2/examples/example-glib.c +++ /dev/null @@ -1,73 +0,0 @@ -#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-1.0.2/examples/example-ivykis.c b/ext/hiredis-1.0.2/examples/example-ivykis.c deleted file mode 100644 index f57dc388..00000000 --- a/ext/hiredis-1.0.2/examples/example-ivykis.c +++ /dev/null @@ -1,60 +0,0 @@ -#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) { -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - - iv_init(); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisIvykisAttach(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"); - - iv_main(); - - iv_deinit(); - - return 0; -} diff --git a/ext/hiredis-1.0.2/examples/example-libev.c b/ext/hiredis-1.0.2/examples/example-libev.c deleted file mode 100644 index ec474306..00000000 --- a/ext/hiredis-1.0.2/examples/example-libev.c +++ /dev/null @@ -1,54 +0,0 @@ -#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) { -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - - 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-1.0.2/examples/example-libevent-ssl.c b/ext/hiredis-1.0.2/examples/example-libevent-ssl.c deleted file mode 100644 index 7d99af1b..00000000 --- a/ext/hiredis-1.0.2/examples/example-libevent-ssl.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#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) { -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - - struct event_base *base = event_base_new(); - if (argc < 5) { - fprintf(stderr, - "Usage: %s [ca]\n", argv[0]); - exit(1); - } - - const char *value = argv[1]; - size_t nvalue = strlen(value); - - const char *hostname = argv[2]; - int port = atoi(argv[3]); - - const char *cert = argv[4]; - const char *certKey = argv[5]; - const char *caCert = argc > 5 ? argv[6] : NULL; - - redisSSLContext *ssl; - redisSSLContextError ssl_error; - - redisInitOpenSSL(); - - ssl = redisCreateSSLContext(caCert, NULL, - cert, certKey, NULL, &ssl_error); - if (!ssl) { - printf("Error: %s\n", redisSSLContextGetError(ssl_error)); - return 1; - } - - redisAsyncContext *c = redisAsyncConnect(hostname, port); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - if (redisInitiateSSLWithContext(&c->c, ssl) != REDIS_OK) { - printf("SSL Error!\n"); - exit(1); - } - - redisLibeventAttach(c,base); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - event_base_dispatch(base); - - redisFreeSSLContext(ssl); - return 0; -} diff --git a/ext/hiredis-1.0.2/examples/example-libevent.c b/ext/hiredis-1.0.2/examples/example-libevent.c deleted file mode 100644 index 49bddd0c..00000000 --- a/ext/hiredis-1.0.2/examples/example-libevent.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) { - if (c->errstr) { - printf("errstr: %s\n", c->errstr); - } - 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) { -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - - struct event_base *base = event_base_new(); - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379); - struct timeval tv = {0}; - tv.tv_sec = 1; - options.connect_timeout = &tv; - - - redisAsyncContext *c = redisAsyncConnectWithOptions(&options); - 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-1.0.2/examples/example-libuv.c b/ext/hiredis-1.0.2/examples/example-libuv.c deleted file mode 100644 index cbde452b..00000000 --- a/ext/hiredis-1.0.2/examples/example-libuv.c +++ /dev/null @@ -1,56 +0,0 @@ -#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) { -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - - 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-1.0.2/examples/example-macosx.c b/ext/hiredis-1.0.2/examples/example-macosx.c deleted file mode 100644 index bc84ed5b..00000000 --- a/ext/hiredis-1.0.2/examples/example-macosx.c +++ /dev/null @@ -1,66 +0,0 @@ -// -// Created by Дмитрий Бахвалов on 13.07.15. -// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. -// - -#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; - } - CFRunLoopStop(CFRunLoopGetCurrent()); - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - CFRunLoopRef loop = CFRunLoopGetCurrent(); - if( !loop ) { - printf("Error: Cannot get current run loop\n"); - return 1; - } - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisMacOSAttach(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"); - - CFRunLoopRun(); - - return 0; -} - diff --git a/ext/hiredis-1.0.2/examples/example-push.c b/ext/hiredis-1.0.2/examples/example-push.c deleted file mode 100644 index 2d4ab4dc..00000000 --- a/ext/hiredis-1.0.2/examples/example-push.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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 - -#define KEY_COUNT 5 - -#define panicAbort(fmt, ...) \ - do { \ - fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); \ - exit(-1); \ - } while (0) - -static void assertReplyAndFree(redisContext *context, redisReply *reply, int type) { - if (reply == NULL) - panicAbort("NULL reply from server (error: %s)", context->errstr); - - if (reply->type != type) { - if (reply->type == REDIS_REPLY_ERROR) - fprintf(stderr, "Redis Error: %s\n", reply->str); - - panicAbort("Expected reply type %d but got type %d", type, reply->type); - } - - freeReplyObject(reply); -} - -/* Switch to the RESP3 protocol and enable client tracking */ -static void enableClientTracking(redisContext *c) { - redisReply *reply = redisCommand(c, "HELLO 3"); - if (reply == NULL || c->err) { - panicAbort("NULL reply or server error (error: %s)", c->errstr); - } - - if (reply->type != REDIS_REPLY_MAP) { - fprintf(stderr, "Error: Can't send HELLO 3 command. Are you sure you're "); - fprintf(stderr, "connected to redis-server >= 6.0.0?\nRedis error: %s\n", - reply->type == REDIS_REPLY_ERROR ? reply->str : "(unknown)"); - exit(-1); - } - - freeReplyObject(reply); - - /* Enable client tracking */ - reply = redisCommand(c, "CLIENT TRACKING ON"); - assertReplyAndFree(c, reply, REDIS_REPLY_STATUS); -} - -void pushReplyHandler(void *privdata, void *r) { - redisReply *reply = r; - int *invalidations = privdata; - - /* Sanity check on the invalidation reply */ - if (reply->type != REDIS_REPLY_PUSH || reply->elements != 2 || - reply->element[1]->type != REDIS_REPLY_ARRAY || - reply->element[1]->element[0]->type != REDIS_REPLY_STRING) - { - panicAbort("%s", "Can't parse PUSH message!"); - } - - /* Increment our invalidation count */ - *invalidations += 1; - - printf("pushReplyHandler(): INVALIDATE '%s' (invalidation count: %d)\n", - reply->element[1]->element[0]->str, *invalidations); - - freeReplyObject(reply); -} - -/* We aren't actually freeing anything here, but it is included to show that we can - * have hiredis call our data destructor when freeing the context */ -void privdata_dtor(void *privdata) { - unsigned int *icount = privdata; - printf("privdata_dtor(): In context privdata dtor (invalidations: %u)\n", *icount); -} - -int main(int argc, char **argv) { - unsigned int j, invalidations = 0; - redisContext *c; - redisReply *reply; - - const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; - int port = (argc > 2) ? atoi(argv[2]) : 6379; - - redisOptions o = {0}; - REDIS_OPTIONS_SET_TCP(&o, hostname, port); - - /* Set our context privdata to the address of our invalidation counter. Each - * time our PUSH handler is called, hiredis will pass the privdata for context. - * - * This could also be done after we create the context like so: - * - * c->privdata = &invalidations; - * c->free_privdata = privdata_dtor; - */ - REDIS_OPTIONS_SET_PRIVDATA(&o, &invalidations, privdata_dtor); - - /* Set our custom PUSH message handler */ - o.push_cb = pushReplyHandler; - - c = redisConnectWithOptions(&o); - if (c == NULL || c->err) - panicAbort("Connection error: %s", c ? c->errstr : "OOM"); - - /* Enable RESP3 and turn on client tracking */ - enableClientTracking(c); - - /* Set some keys and then read them back. Once we do that, Redis will deliver - * invalidation push messages whenever the key is modified */ - for (j = 0; j < KEY_COUNT; j++) { - reply = redisCommand(c, "SET key:%d initial:%d", j, j); - assertReplyAndFree(c, reply, REDIS_REPLY_STATUS); - - reply = redisCommand(c, "GET key:%d", j); - assertReplyAndFree(c, reply, REDIS_REPLY_STRING); - } - - /* Trigger invalidation messages by updating keys we just read */ - for (j = 0; j < KEY_COUNT; j++) { - printf(" main(): SET key:%d update:%d\n", j, j); - reply = redisCommand(c, "SET key:%d update:%d", j, j); - assertReplyAndFree(c, reply, REDIS_REPLY_STATUS); - printf(" main(): SET REPLY OK\n"); - } - - printf("\nTotal detected invalidations: %d, expected: %d\n", invalidations, KEY_COUNT); - - /* PING server */ - redisFree(c); -} diff --git a/ext/hiredis-1.0.2/examples/example-qt.cpp b/ext/hiredis-1.0.2/examples/example-qt.cpp deleted file mode 100644 index f524c3f3..00000000 --- a/ext/hiredis-1.0.2/examples/example-qt.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -using namespace std; - -#include -#include - -#include "example-qt.h" - -void getCallback(redisAsyncContext *, void * r, void * privdata) { - - redisReply * reply = static_cast(r); - ExampleQt * ex = static_cast(privdata); - if (reply == nullptr || ex == nullptr) return; - - cout << "key: " << reply->str << endl; - - ex->finish(); -} - -void ExampleQt::run() { - - m_ctx = redisAsyncConnect("localhost", 6379); - - if (m_ctx->err) { - cerr << "Error: " << m_ctx->errstr << endl; - redisAsyncFree(m_ctx); - emit finished(); - } - - m_adapter.setContext(m_ctx); - - redisAsyncCommand(m_ctx, NULL, NULL, "SET key %s", m_value); - redisAsyncCommand(m_ctx, getCallback, this, "GET key"); -} - -int main (int argc, char **argv) { - - QCoreApplication app(argc, argv); - - ExampleQt example(argv[argc-1]); - - QObject::connect(&example, SIGNAL(finished()), &app, SLOT(quit())); - QTimer::singleShot(0, &example, SLOT(run())); - - return app.exec(); -} diff --git a/ext/hiredis-1.0.2/examples/example-qt.h b/ext/hiredis-1.0.2/examples/example-qt.h deleted file mode 100644 index 374f4766..00000000 --- a/ext/hiredis-1.0.2/examples/example-qt.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __HIREDIS_EXAMPLE_QT_H -#define __HIREDIS_EXAMPLE_QT_H - -#include - -class ExampleQt : public QObject { - - Q_OBJECT - - public: - ExampleQt(const char * value, QObject * parent = 0) - : QObject(parent), m_value(value) {} - - signals: - void finished(); - - public slots: - void run(); - - private: - void finish() { emit finished(); } - - private: - const char * m_value; - redisAsyncContext * m_ctx; - RedisQtAdapter m_adapter; - - friend - void getCallback(redisAsyncContext *, void *, void *); -}; - -#endif /* !__HIREDIS_EXAMPLE_QT_H */ diff --git a/ext/hiredis-1.0.2/examples/example-ssl.c b/ext/hiredis-1.0.2/examples/example-ssl.c deleted file mode 100644 index c754177c..00000000 --- a/ext/hiredis-1.0.2/examples/example-ssl.c +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -int main(int argc, char **argv) { - unsigned int j; - redisSSLContext *ssl; - redisSSLContextError ssl_error; - redisContext *c; - redisReply *reply; - if (argc < 4) { - printf("Usage: %s [ca]\n", argv[0]); - exit(1); - } - const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; - int port = atoi(argv[2]); - const char *cert = argv[3]; - const char *key = argv[4]; - const char *ca = argc > 4 ? argv[5] : NULL; - - redisInitOpenSSL(); - ssl = redisCreateSSLContext(ca, NULL, cert, key, NULL, &ssl_error); - if (!ssl) { - printf("SSL Context error: %s\n", - redisSSLContextGetError(ssl_error)); - exit(1); - } - - struct timeval tv = { 1, 500000 }; // 1.5 seconds - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, hostname, port); - options.connect_timeout = &tv; - c = redisConnectWithOptions(&options); - - 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); - } - - if (redisInitiateSSLWithContext(c, ssl) != REDIS_OK) { - printf("Couldn't initialize SSL!\n"); - printf("Error: %s\n", c->errstr); - redisFree(c); - 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,"%u",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); - - redisFreeSSLContext(ssl); - - return 0; -} diff --git a/ext/hiredis-1.0.2/examples/example.c b/ext/hiredis-1.0.2/examples/example.c deleted file mode 100644 index 15dacbd1..00000000 --- a/ext/hiredis-1.0.2/examples/example.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include -#include - -int main(int argc, char **argv) { - unsigned int j, isunix = 0; - redisContext *c; - redisReply *reply; - const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; - - if (argc > 2) { - if (*argv[2] == 'u' || *argv[2] == 'U') { - isunix = 1; - /* in this case, host is the path to the unix socket */ - printf("Will connect to unix socket @%s\n", hostname); - } - } - - int port = (argc > 2) ? atoi(argv[2]) : 6379; - - struct timeval timeout = { 1, 500000 }; // 1.5 seconds - if (isunix) { - c = redisConnectUnixWithTimeout(hostname, timeout); - } else { - 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,"%u",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-1.0.2/fmacros.h b/ext/hiredis-1.0.2/fmacros.h deleted file mode 100644 index 3227faaf..00000000 --- a/ext/hiredis-1.0.2/fmacros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __HIREDIS_FMACRO_H -#define __HIREDIS_FMACRO_H - -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L - -#if defined(__APPLE__) && defined(__MACH__) -/* Enable TCP_KEEPALIVE */ -#define _DARWIN_C_SOURCE -#endif - -#endif diff --git a/ext/hiredis-1.0.2/hiredis-config.cmake.in b/ext/hiredis-1.0.2/hiredis-config.cmake.in deleted file mode 100644 index 98851dce..00000000 --- a/ext/hiredis-1.0.2/hiredis-config.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -@PACKAGE_INIT@ - -set_and_check(hiredis_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@") - -IF (NOT TARGET hiredis::hiredis) - INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis-targets.cmake) -ENDIF() - -SET(hiredis_LIBRARIES hiredis::hiredis) -SET(hiredis_INCLUDE_DIRS ${hiredis_INCLUDEDIR}) - -check_required_components(hiredis) - diff --git a/ext/hiredis-1.0.2/hiredis.c b/ext/hiredis-1.0.2/hiredis.c deleted file mode 100644 index ab0e3982..00000000 --- a/ext/hiredis-1.0.2/hiredis.c +++ /dev/null @@ -1,1174 +0,0 @@ -/* - * 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 "hiredis.h" -#include "net.h" -#include "sds.h" -#include "async.h" -#include "win32.h" - -extern int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout); -extern int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout); - -static redisContextFuncs redisContextDefaultFuncs = { - .free_privctx = NULL, - .async_read = redisAsyncRead, - .async_write = redisAsyncWrite, - .read = redisNetRead, - .write = redisNetWrite -}; - -static redisReply *createReplyObject(int type); -static void *createStringObject(const redisReadTask *task, char *str, size_t len); -static void *createArrayObject(const redisReadTask *task, size_t elements); -static void *createIntegerObject(const redisReadTask *task, long long value); -static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len); -static void *createNilObject(const redisReadTask *task); -static void *createBoolObject(const redisReadTask *task, int bval); - -/* 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, - createDoubleObject, - createNilObject, - createBoolObject, - freeReplyObject -}; - -/* Create a reply object */ -static redisReply *createReplyObject(int type) { - redisReply *r = hi_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: - case REDIS_REPLY_MAP: - case REDIS_REPLY_SET: - case REDIS_REPLY_PUSH: - if (r->element != NULL) { - for (j = 0; j < r->elements; j++) - freeReplyObject(r->element[j]); - hi_free(r->element); - } - break; - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_STRING: - case REDIS_REPLY_DOUBLE: - case REDIS_REPLY_VERB: - hi_free(r->str); - break; - } - hi_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; - - assert(task->type == REDIS_REPLY_ERROR || - task->type == REDIS_REPLY_STATUS || - task->type == REDIS_REPLY_STRING || - task->type == REDIS_REPLY_VERB); - - /* Copy string value */ - if (task->type == REDIS_REPLY_VERB) { - buf = hi_malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */ - if (buf == NULL) goto oom; - - memcpy(r->vtype,str,3); - r->vtype[3] = '\0'; - memcpy(buf,str+4,len-4); - buf[len-4] = '\0'; - r->len = len - 4; - } else { - buf = hi_malloc(len+1); - if (buf == NULL) goto oom; - - memcpy(buf,str,len); - buf[len] = '\0'; - r->len = len; - } - r->str = buf; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; - -oom: - freeReplyObject(r); - return NULL; -} - -static void *createArrayObject(const redisReadTask *task, size_t elements) { - redisReply *r, *parent; - - r = createReplyObject(task->type); - if (r == NULL) - return NULL; - - if (elements > 0) { - if (SIZE_MAX / sizeof(redisReply*) < elements) return NULL; /* Don't overflow */ - r->element = hi_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->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - 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->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET || - parent->type == REDIS_REPLY_PUSH); - parent->element[task->idx] = r; - } - return r; -} - -static void *createDoubleObject(const redisReadTask *task, double value, char *str, size_t len) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_DOUBLE); - if (r == NULL) - return NULL; - - r->dval = value; - r->str = hi_malloc(len+1); - if (r->str == NULL) { - freeReplyObject(r); - return NULL; - } - - /* The double reply also has the original protocol string representing a - * double as a null terminated string. This way the caller does not need - * to format back for string conversion, especially since Redis does efforts - * to make the string more human readable avoiding the calssical double - * decimal string conversion artifacts. */ - memcpy(r->str, str, len); - r->str[len] = '\0'; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - 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->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - parent->element[task->idx] = r; - } - return r; -} - -static void *createBoolObject(const redisReadTask *task, int bval) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_BOOL); - if (r == NULL) - return NULL; - - r->integer = bval != 0; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY || - parent->type == REDIS_REPLY_MAP || - parent->type == REDIS_REPLY_SET); - 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 = hi_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 = hi_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 = hi_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'; - - hi_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]); - hi_free(curargv); - } - - sdsfree(curarg); - hi_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, aux; - 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 */ - aux = sdsMakeRoomFor(cmd, totlen); - if (aux == NULL) { - sdsfree(cmd); - return -1; - } - - cmd = aux; - - /* 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, "$%u\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 = hi_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) { - hi_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); - strerror_r(errno, c->errstr, sizeof(c->errstr)); - } -} - -redisReader *redisReaderCreate(void) { - return redisReaderCreateWithFunctions(&defaultFunctions); -} - -static void redisPushAutoFree(void *privdata, void *reply) { - (void)privdata; - freeReplyObject(reply); -} - -static redisContext *redisContextInit(void) { - redisContext *c; - - c = hi_calloc(1, sizeof(*c)); - if (c == NULL) - return NULL; - - c->funcs = &redisContextDefaultFuncs; - - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - c->fd = REDIS_INVALID_FD; - - if (c->obuf == NULL || c->reader == NULL) { - redisFree(c); - return NULL; - } - - return c; -} - -void redisFree(redisContext *c) { - if (c == NULL) - return; - redisNetClose(c); - - sdsfree(c->obuf); - redisReaderFree(c->reader); - hi_free(c->tcp.host); - hi_free(c->tcp.source_addr); - hi_free(c->unix_sock.path); - hi_free(c->connect_timeout); - hi_free(c->command_timeout); - hi_free(c->saddr); - - if (c->privdata && c->free_privdata) - c->free_privdata(c->privdata); - - if (c->funcs->free_privctx) - c->funcs->free_privctx(c->privctx); - - memset(c, 0xff, sizeof(*c)); - hi_free(c); -} - -redisFD redisFreeKeepFd(redisContext *c) { - redisFD fd = c->fd; - c->fd = REDIS_INVALID_FD; - redisFree(c); - return fd; -} - -int redisReconnect(redisContext *c) { - c->err = 0; - memset(c->errstr, '\0', strlen(c->errstr)); - - if (c->privctx && c->funcs->free_privctx) { - c->funcs->free_privctx(c->privctx); - c->privctx = NULL; - } - - redisNetClose(c); - - sdsfree(c->obuf); - redisReaderFree(c->reader); - - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - - if (c->obuf == NULL || c->reader == NULL) { - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; - } - - int ret = REDIS_ERR; - if (c->connection_type == REDIS_CONN_TCP) { - ret = redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, - c->connect_timeout, c->tcp.source_addr); - } else if (c->connection_type == REDIS_CONN_UNIX) { - ret = redisContextConnectUnix(c, c->unix_sock.path, c->connect_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"); - ret = REDIS_ERR; - } - - if (c->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) { - redisContextSetTimeout(c, *c->command_timeout); - } - - return ret; -} - -redisContext *redisConnectWithOptions(const redisOptions *options) { - redisContext *c = redisContextInit(); - if (c == NULL) { - return NULL; - } - if (!(options->options & REDIS_OPT_NONBLOCK)) { - c->flags |= REDIS_BLOCK; - } - if (options->options & REDIS_OPT_REUSEADDR) { - c->flags |= REDIS_REUSEADDR; - } - if (options->options & REDIS_OPT_NOAUTOFREE) { - c->flags |= REDIS_NO_AUTO_FREE; - } - - /* Set any user supplied RESP3 PUSH handler or use freeReplyObject - * as a default unless specifically flagged that we don't want one. */ - if (options->push_cb != NULL) - redisSetPushCallback(c, options->push_cb); - else if (!(options->options & REDIS_OPT_NO_PUSH_AUTOFREE)) - redisSetPushCallback(c, redisPushAutoFree); - - c->privdata = options->privdata; - c->free_privdata = options->free_privdata; - - if (redisContextUpdateConnectTimeout(c, options->connect_timeout) != REDIS_OK || - redisContextUpdateCommandTimeout(c, options->command_timeout) != REDIS_OK) { - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return c; - } - - if (options->type == REDIS_CONN_TCP) { - redisContextConnectBindTcp(c, options->endpoint.tcp.ip, - options->endpoint.tcp.port, options->connect_timeout, - options->endpoint.tcp.source_addr); - } else if (options->type == REDIS_CONN_UNIX) { - redisContextConnectUnix(c, options->endpoint.unix_socket, - options->connect_timeout); - } else if (options->type == REDIS_CONN_USERFD) { - c->fd = options->endpoint.fd; - c->flags |= REDIS_CONNECTED; - } else { - // Unknown type - FIXME - FREE - return NULL; - } - - if (options->command_timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) { - redisContextSetTimeout(c, *options->command_timeout); - } - - return c; -} - -/* 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) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.connect_timeout = &tv; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectNonBlock(const char *ip, int port) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectBindNonBlock(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, - const char *source_addr) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, ip, port); - options.endpoint.tcp.source_addr = source_addr; - options.options |= REDIS_OPT_NONBLOCK|REDIS_OPT_REUSEADDR; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnix(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - options.connect_timeout = &tv; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectUnixNonBlock(const char *path) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_UNIX(&options, path); - options.options |= REDIS_OPT_NONBLOCK; - return redisConnectWithOptions(&options); -} - -redisContext *redisConnectFd(redisFD fd) { - redisOptions options = {0}; - options.type = REDIS_CONN_USERFD; - options.endpoint.fd = fd; - return redisConnectWithOptions(&options); -} - -/* 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; -} - -/* Set a user provided RESP3 PUSH handler and return any old one set. */ -redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn) { - redisPushFn *old = c->push_cb; - c->push_cb = fn; - return old; -} - -/* 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 redisGetReplyFromReader 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 = c->funcs->read(c, buf, sizeof(buf)); - if (nread > 0) { - if (redisReaderFeed(c->reader, buf, nread) != REDIS_OK) { - __redisSetError(c, c->reader->err, c->reader->errstr); - return REDIS_ERR; - } else { - } - } else if (nread < 0) { - 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 - * successfully 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 occurred trying to write and sets - * c->errstr to hold the appropriate error string. - */ -int redisBufferWrite(redisContext *c, int *done) { - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - if (sdslen(c->obuf) > 0) { - ssize_t nwritten = c->funcs->write(c); - if (nwritten < 0) { - return REDIS_ERR; - } else if (nwritten > 0) { - if (nwritten == (ssize_t)sdslen(c->obuf)) { - sdsfree(c->obuf); - c->obuf = sdsempty(); - if (c->obuf == NULL) - goto oom; - } else { - if (sdsrange(c->obuf,nwritten,-1) < 0) goto oom; - } - } - } - if (done != NULL) *done = (sdslen(c->obuf) == 0); - return REDIS_OK; - -oom: - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; -} - -/* 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; -} - -/* Internal helper that returns 1 if the reply was a RESP3 PUSH - * message and we handled it with a user-provided callback. */ -static int redisHandledPushReply(redisContext *c, void *reply) { - if (reply && c->push_cb && redisIsPushReply(reply)) { - c->push_cb(c->privdata, reply); - return 1; - } - - return 0; -} - -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; - - /* We loop here in case the user has specified a RESP3 - * PUSH handler (e.g. for client tracking). */ - do { - if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - } while (redisHandledPushReply(c, aux)); - } while (aux == NULL); - } - - /* Set reply or free it if we were passed NULL */ - if (reply != NULL) { - *reply = aux; - } else { - freeReplyObject(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) { - hi_free(cmd); - return REDIS_ERR; - } - - hi_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 successfully 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; - va_start(ap,format); - void *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-1.0.2/hiredis.h b/ext/hiredis-1.0.2/hiredis.h deleted file mode 100644 index 3bc46d99..00000000 --- a/ext/hiredis-1.0.2/hiredis.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * 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 */ -#ifndef _MSC_VER -#include /* for struct timeval */ -#else -struct timeval; /* forward declaration */ -typedef long long ssize_t; -#endif -#include /* uintXX_t, etc */ -#include "sds.h" /* for sds */ -#include "alloc.h" /* for allocation wrappers */ - -#define HIREDIS_MAJOR 1 -#define HIREDIS_MINOR 0 -#define HIREDIS_PATCH 2 -#define HIREDIS_SONAME 1.0.0 - -/* 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 - -/** - * Flag that indicates the user does not want the context to - * be automatically freed upon error - */ -#define REDIS_NO_AUTO_FREE 0x200 - -#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 - -/* Forward declarations for structs defined elsewhere */ -struct redisAsyncContext; -struct redisContext; - -/* RESP3 push helpers and callback prototypes */ -#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH) -typedef void (redisPushFn)(void *, void *); -typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *); - -#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 */ - double dval; /* The double when type is REDIS_REPLY_DOUBLE */ - size_t len; /* Length of string */ - char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING - REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */ - char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null - terminated 3 character content type, such as "txt". */ - 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, - REDIS_CONN_USERFD -}; - -struct redisSsl; - -#define REDIS_OPT_NONBLOCK 0x01 -#define REDIS_OPT_REUSEADDR 0x02 - -/** - * Don't automatically free the async object on a connection failure, - * or other implicit conditions. Only free on an explicit call to disconnect() or free() - */ -#define REDIS_OPT_NOAUTOFREE 0x04 - -/* Don't automatically intercept and free RESP3 PUSH replies. */ -#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08 - -/* In Unix systems a file descriptor is a regular signed int, with -1 - * representing an invalid descriptor. In Windows it is a SOCKET - * (32- or 64-bit unsigned integer depending on the architecture), where - * all bits set (~0) is INVALID_SOCKET. */ -#ifndef _WIN32 -typedef int redisFD; -#define REDIS_INVALID_FD -1 -#else -#ifdef _WIN64 -typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */ -#else -typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */ -#endif -#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */ -#endif - -typedef struct { - /* - * the type of connection to use. This also indicates which - * `endpoint` member field to use - */ - int type; - /* bit field of REDIS_OPT_xxx */ - int options; - /* timeout value for connect operation. If NULL, no timeout is used */ - const struct timeval *connect_timeout; - /* timeout value for commands. If NULL, no timeout is used. This can be - * updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */ - const struct timeval *command_timeout; - union { - /** use this field for tcp/ip connections */ - struct { - const char *source_addr; - const char *ip; - int port; - } tcp; - /** use this field for unix domain sockets */ - const char *unix_socket; - /** - * use this field to have hiredis operate an already-open - * file descriptor */ - redisFD fd; - } endpoint; - - /* Optional user defined data/destructor */ - void *privdata; - void (*free_privdata)(void *); - - /* A user defined PUSH message callback */ - redisPushFn *push_cb; - redisAsyncPushFn *async_push_cb; -} redisOptions; - -/** - * Helper macros to initialize options to their specified fields. - */ -#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \ - (opts)->type = REDIS_CONN_TCP; \ - (opts)->endpoint.tcp.ip = ip_; \ - (opts)->endpoint.tcp.port = port_; - -#define REDIS_OPTIONS_SET_UNIX(opts, path) \ - (opts)->type = REDIS_CONN_UNIX; \ - (opts)->endpoint.unix_socket = path; - -#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \ - (opts)->privdata = data; \ - (opts)->free_privdata = dtor; \ - -typedef struct redisContextFuncs { - void (*free_privctx)(void *); - void (*async_read)(struct redisAsyncContext *); - void (*async_write)(struct redisAsyncContext *); - ssize_t (*read)(struct redisContext *, char *, size_t); - ssize_t (*write)(struct redisContext *); -} redisContextFuncs; - -/* Context for a connection to Redis */ -typedef struct redisContext { - const redisContextFuncs *funcs; /* Function table */ - - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - redisFD fd; - int flags; - char *obuf; /* Write buffer */ - redisReader *reader; /* Protocol reader */ - - enum redisConnectionType connection_type; - struct timeval *connect_timeout; - struct timeval *command_timeout; - - struct { - char *host; - char *source_addr; - int port; - } tcp; - - struct { - char *path; - } unix_sock; - - /* For non-blocking connect */ - struct sockadr *saddr; - size_t addrlen; - - /* Optional data and corresponding destructor users can use to provide - * context to a given redisContext. Not used by hiredis. */ - void *privdata; - void (*free_privdata)(void *); - - /* Internal context pointer presently used by hiredis to manage - * SSL connections. */ - void *privctx; - - /* An optional RESP3 PUSH handler */ - redisPushFn *push_cb; -} redisContext; - -redisContext *redisConnectWithOptions(const redisOptions *options); -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(redisFD 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 successful connect or REDIS_ERR otherwise. - */ -int redisReconnect(redisContext *c); - -redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); -int redisSetTimeout(redisContext *c, const struct timeval tv); -int redisEnableKeepAlive(redisContext *c); -void redisFree(redisContext *c); -redisFD 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-1.0.2/hiredis.pc.in b/ext/hiredis-1.0.2/hiredis.pc.in deleted file mode 100644 index 91b77318..00000000 --- a/ext/hiredis-1.0.2/hiredis.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -install_libdir=@CMAKE_INSTALL_LIBDIR@ -exec_prefix=${prefix} -libdir=${exec_prefix}/${install_libdir} -includedir=${prefix}/include -pkgincludedir=${includedir}/hiredis - -Name: hiredis -Description: Minimalistic C client library for Redis. -Version: @PROJECT_VERSION@ -Libs: -L${libdir} -lhiredis -Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64 diff --git a/ext/hiredis-1.0.2/hiredis_ssl-config.cmake.in b/ext/hiredis-1.0.2/hiredis_ssl-config.cmake.in deleted file mode 100644 index 9a283dfc..00000000 --- a/ext/hiredis-1.0.2/hiredis_ssl-config.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -@PACKAGE_INIT@ - -set_and_check(hiredis_ssl_INCLUDEDIR "@PACKAGE_INCLUDE_INSTALL_DIR@") - -IF (NOT TARGET hiredis::hiredis_ssl) - INCLUDE(${CMAKE_CURRENT_LIST_DIR}/hiredis_ssl-targets.cmake) -ENDIF() - -SET(hiredis_ssl_LIBRARIES hiredis::hiredis_ssl) -SET(hiredis_ssl_INCLUDE_DIRS ${hiredis_ssl_INCLUDEDIR}) - -check_required_components(hiredis_ssl) - diff --git a/ext/hiredis-1.0.2/hiredis_ssl.h b/ext/hiredis-1.0.2/hiredis_ssl.h deleted file mode 100644 index 604efe0c..00000000 --- a/ext/hiredis-1.0.2/hiredis_ssl.h +++ /dev/null @@ -1,127 +0,0 @@ - -/* - * Copyright (c) 2019, Redis Labs - * - * 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_SSL_H -#define __HIREDIS_SSL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the underlying struct for SSL in ssl.h, which is not included to - * keep build dependencies short here. - */ -struct ssl_st; - -/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly - * calling OpenSSL. - */ -typedef struct redisSSLContext redisSSLContext; - -/** - * Initialization errors that redisCreateSSLContext() may return. - */ - -typedef enum { - REDIS_SSL_CTX_NONE = 0, /* No Error */ - REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */ - REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */ - REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */ - REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ - REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */ -} redisSSLContextError; - -/** - * Return the error message corresponding with the specified error code. - */ - -const char *redisSSLContextGetError(redisSSLContextError error); - -/** - * Helper function to initialize the OpenSSL library. - * - * OpenSSL requires one-time initialization before it can be used. Callers should - * call this function only once, and only if OpenSSL is not directly initialized - * elsewhere. - */ -int redisInitOpenSSL(void); - -/** - * Helper function to initialize an OpenSSL context that can be used - * to initiate SSL connections. - * - * cacert_filename is an optional name of a CA certificate/bundle file to load - * and use for validation. - * - * capath is an optional directory path where trusted CA certificate files are - * stored in an OpenSSL-compatible structure. - * - * cert_filename and private_key_filename are optional names of a client side - * certificate and private key files to use for authentication. They need to - * be both specified or omitted. - * - * server_name is an optional and will be used as a server name indication - * (SNI) TLS extension. - * - * If error is non-null, it will be populated in case the context creation fails - * (returning a NULL). - */ - -redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath, - const char *cert_filename, const char *private_key_filename, - const char *server_name, redisSSLContextError *error); - -/** - * Free a previously created OpenSSL context. - */ -void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx); - -/** - * Initiate SSL on an existing redisContext. - * - * This is similar to redisInitiateSSL() but does not require the caller - * to directly interact with OpenSSL, and instead uses a redisSSLContext - * previously created using redisCreateSSLContext(). - */ - -int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx); - -/** - * Initiate SSL/TLS negotiation on a provided OpenSSL SSL object. - */ - -int redisInitiateSSL(redisContext *c, struct ssl_st *ssl); - -#ifdef __cplusplus -} -#endif - -#endif /* __HIREDIS_SSL_H */ diff --git a/ext/hiredis-1.0.2/hiredis_ssl.pc.in b/ext/hiredis-1.0.2/hiredis_ssl.pc.in deleted file mode 100644 index 588a978a..00000000 --- a/ext/hiredis-1.0.2/hiredis_ssl.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include -pkgincludedir=${includedir}/hiredis - -Name: hiredis_ssl -Description: SSL Support for hiredis. -Version: @PROJECT_VERSION@ -Requires: hiredis -Libs: -L${libdir} -lhiredis_ssl -Libs.private: -lssl -lcrypto diff --git a/ext/hiredis-1.0.2/include/hiredis/alloc.h b/ext/hiredis-1.0.2/include/hiredis/alloc.h deleted file mode 100644 index 34a05f49..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/alloc.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2020, Michael Grunder - * - * 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_ALLOC_H -#define HIREDIS_ALLOC_H - -#include /* for size_t */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure pointing to our actually configured allocators */ -typedef struct hiredisAllocFuncs { - void *(*mallocFn)(size_t); - void *(*callocFn)(size_t,size_t); - void *(*reallocFn)(void*,size_t); - char *(*strdupFn)(const char*); - void (*freeFn)(void*); -} hiredisAllocFuncs; - -hiredisAllocFuncs hiredisSetAllocators(hiredisAllocFuncs *ha); -void hiredisResetAllocators(void); - -#ifndef _WIN32 - -/* Hiredis' configured allocator function pointer struct */ -extern hiredisAllocFuncs hiredisAllocFns; - -static inline void *hi_malloc(size_t size) { - return hiredisAllocFns.mallocFn(size); -} - -static inline void *hi_calloc(size_t nmemb, size_t size) { - return hiredisAllocFns.callocFn(nmemb, size); -} - -static inline void *hi_realloc(void *ptr, size_t size) { - return hiredisAllocFns.reallocFn(ptr, size); -} - -static inline char *hi_strdup(const char *str) { - return hiredisAllocFns.strdupFn(str); -} - -static inline void hi_free(void *ptr) { - hiredisAllocFns.freeFn(ptr); -} - -#else - -void *hi_malloc(size_t size); -void *hi_calloc(size_t nmemb, size_t size); -void *hi_realloc(void *ptr, size_t size); -char *hi_strdup(const char *str); -void hi_free(void *ptr); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* HIREDIS_ALLOC_H */ diff --git a/ext/hiredis-1.0.2/include/hiredis/async.h b/ext/hiredis-1.0.2/include/hiredis/async.h deleted file mode 100644 index b1d2cb26..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/async.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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; - int pending_subs; - 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); -typedef void(redisTimerCallback)(void *timer, void *privdata); - -/* 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 (*dataCleanup)(void *privdata); - - /* 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); - void (*scheduleTimer)(void *privdata, struct timeval tv); - } 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; - - /* Address used for connect() */ - struct sockaddr *saddr; - size_t addrlen; - - /* Subscription callbacks */ - struct { - redisCallbackList invalid; - struct dict *channels; - struct dict *patterns; - } sub; - - /* Any configured RESP3 PUSH handler */ - redisAsyncPushFn *push_cb; -} redisAsyncContext; - -/* Functions that proxy to hiredis */ -redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options); -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); - -redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn); -int redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv); -void redisAsyncDisconnect(redisAsyncContext *ac); -void redisAsyncFree(redisAsyncContext *ac); - -/* Handle read/write events */ -void redisAsyncHandleRead(redisAsyncContext *ac); -void redisAsyncHandleWrite(redisAsyncContext *ac); -void redisAsyncHandleTimeout(redisAsyncContext *ac); -void redisAsyncRead(redisAsyncContext *ac); -void redisAsyncWrite(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-1.0.2/include/hiredis/async_private.h b/ext/hiredis-1.0.2/include/hiredis/async_private.h deleted file mode 100644 index b9d23fff..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/async_private.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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_PRIVATE_H -#define __HIREDIS_ASYNC_PRIVATE_H - -#define _EL_ADD_READ(ctx) \ - do { \ - refreshTimeout(ctx); \ - 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 { \ - refreshTimeout(ctx); \ - 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); \ - ctx->ev.cleanup = NULL; \ - } while(0); - -static inline void refreshTimeout(redisAsyncContext *ctx) { - #define REDIS_TIMER_ISSET(tvp) \ - (tvp && ((tvp)->tv_sec || (tvp)->tv_usec)) - - #define REDIS_EL_TIMER(ac, tvp) \ - if ((ac)->ev.scheduleTimer && REDIS_TIMER_ISSET(tvp)) { \ - (ac)->ev.scheduleTimer((ac)->ev.data, *(tvp)); \ - } - - if (ctx->c.flags & REDIS_CONNECTED) { - REDIS_EL_TIMER(ctx, ctx->c.command_timeout); - } else { - REDIS_EL_TIMER(ctx, ctx->c.connect_timeout); - } -} - -void __redisAsyncDisconnect(redisAsyncContext *ac); -void redisProcessCallbacks(redisAsyncContext *ac); - -#endif /* __HIREDIS_ASYNC_PRIVATE_H */ diff --git a/ext/hiredis-1.0.2/include/hiredis/dict.h b/ext/hiredis-1.0.2/include/hiredis/dict.h deleted file mode 100644 index 95fcd280..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/dict.h +++ /dev/null @@ -1,126 +0,0 @@ -/* 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-1.0.2/include/hiredis/fmacros.h b/ext/hiredis-1.0.2/include/hiredis/fmacros.h deleted file mode 100644 index 3227faaf..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/fmacros.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __HIREDIS_FMACRO_H -#define __HIREDIS_FMACRO_H - -#define _XOPEN_SOURCE 600 -#define _POSIX_C_SOURCE 200112L - -#if defined(__APPLE__) && defined(__MACH__) -/* Enable TCP_KEEPALIVE */ -#define _DARWIN_C_SOURCE -#endif - -#endif diff --git a/ext/hiredis-1.0.2/include/hiredis/hiredis.h b/ext/hiredis-1.0.2/include/hiredis/hiredis.h deleted file mode 100644 index 3bc46d99..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/hiredis.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * 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 */ -#ifndef _MSC_VER -#include /* for struct timeval */ -#else -struct timeval; /* forward declaration */ -typedef long long ssize_t; -#endif -#include /* uintXX_t, etc */ -#include "sds.h" /* for sds */ -#include "alloc.h" /* for allocation wrappers */ - -#define HIREDIS_MAJOR 1 -#define HIREDIS_MINOR 0 -#define HIREDIS_PATCH 2 -#define HIREDIS_SONAME 1.0.0 - -/* 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 - -/** - * Flag that indicates the user does not want the context to - * be automatically freed upon error - */ -#define REDIS_NO_AUTO_FREE 0x200 - -#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 - -/* Forward declarations for structs defined elsewhere */ -struct redisAsyncContext; -struct redisContext; - -/* RESP3 push helpers and callback prototypes */ -#define redisIsPushReply(r) (((redisReply*)(r))->type == REDIS_REPLY_PUSH) -typedef void (redisPushFn)(void *, void *); -typedef void (redisAsyncPushFn)(struct redisAsyncContext *, void *); - -#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 */ - double dval; /* The double when type is REDIS_REPLY_DOUBLE */ - size_t len; /* Length of string */ - char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING - REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */ - char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null - terminated 3 character content type, such as "txt". */ - 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, - REDIS_CONN_USERFD -}; - -struct redisSsl; - -#define REDIS_OPT_NONBLOCK 0x01 -#define REDIS_OPT_REUSEADDR 0x02 - -/** - * Don't automatically free the async object on a connection failure, - * or other implicit conditions. Only free on an explicit call to disconnect() or free() - */ -#define REDIS_OPT_NOAUTOFREE 0x04 - -/* Don't automatically intercept and free RESP3 PUSH replies. */ -#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08 - -/* In Unix systems a file descriptor is a regular signed int, with -1 - * representing an invalid descriptor. In Windows it is a SOCKET - * (32- or 64-bit unsigned integer depending on the architecture), where - * all bits set (~0) is INVALID_SOCKET. */ -#ifndef _WIN32 -typedef int redisFD; -#define REDIS_INVALID_FD -1 -#else -#ifdef _WIN64 -typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */ -#else -typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */ -#endif -#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */ -#endif - -typedef struct { - /* - * the type of connection to use. This also indicates which - * `endpoint` member field to use - */ - int type; - /* bit field of REDIS_OPT_xxx */ - int options; - /* timeout value for connect operation. If NULL, no timeout is used */ - const struct timeval *connect_timeout; - /* timeout value for commands. If NULL, no timeout is used. This can be - * updated at runtime with redisSetTimeout/redisAsyncSetTimeout. */ - const struct timeval *command_timeout; - union { - /** use this field for tcp/ip connections */ - struct { - const char *source_addr; - const char *ip; - int port; - } tcp; - /** use this field for unix domain sockets */ - const char *unix_socket; - /** - * use this field to have hiredis operate an already-open - * file descriptor */ - redisFD fd; - } endpoint; - - /* Optional user defined data/destructor */ - void *privdata; - void (*free_privdata)(void *); - - /* A user defined PUSH message callback */ - redisPushFn *push_cb; - redisAsyncPushFn *async_push_cb; -} redisOptions; - -/** - * Helper macros to initialize options to their specified fields. - */ -#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \ - (opts)->type = REDIS_CONN_TCP; \ - (opts)->endpoint.tcp.ip = ip_; \ - (opts)->endpoint.tcp.port = port_; - -#define REDIS_OPTIONS_SET_UNIX(opts, path) \ - (opts)->type = REDIS_CONN_UNIX; \ - (opts)->endpoint.unix_socket = path; - -#define REDIS_OPTIONS_SET_PRIVDATA(opts, data, dtor) \ - (opts)->privdata = data; \ - (opts)->free_privdata = dtor; \ - -typedef struct redisContextFuncs { - void (*free_privctx)(void *); - void (*async_read)(struct redisAsyncContext *); - void (*async_write)(struct redisAsyncContext *); - ssize_t (*read)(struct redisContext *, char *, size_t); - ssize_t (*write)(struct redisContext *); -} redisContextFuncs; - -/* Context for a connection to Redis */ -typedef struct redisContext { - const redisContextFuncs *funcs; /* Function table */ - - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - redisFD fd; - int flags; - char *obuf; /* Write buffer */ - redisReader *reader; /* Protocol reader */ - - enum redisConnectionType connection_type; - struct timeval *connect_timeout; - struct timeval *command_timeout; - - struct { - char *host; - char *source_addr; - int port; - } tcp; - - struct { - char *path; - } unix_sock; - - /* For non-blocking connect */ - struct sockadr *saddr; - size_t addrlen; - - /* Optional data and corresponding destructor users can use to provide - * context to a given redisContext. Not used by hiredis. */ - void *privdata; - void (*free_privdata)(void *); - - /* Internal context pointer presently used by hiredis to manage - * SSL connections. */ - void *privctx; - - /* An optional RESP3 PUSH handler */ - redisPushFn *push_cb; -} redisContext; - -redisContext *redisConnectWithOptions(const redisOptions *options); -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(redisFD 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 successful connect or REDIS_ERR otherwise. - */ -int redisReconnect(redisContext *c); - -redisPushFn *redisSetPushCallback(redisContext *c, redisPushFn *fn); -int redisSetTimeout(redisContext *c, const struct timeval tv); -int redisEnableKeepAlive(redisContext *c); -void redisFree(redisContext *c); -redisFD 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-1.0.2/include/hiredis/hiredis_ssl.h b/ext/hiredis-1.0.2/include/hiredis/hiredis_ssl.h deleted file mode 100644 index 604efe0c..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/hiredis_ssl.h +++ /dev/null @@ -1,127 +0,0 @@ - -/* - * Copyright (c) 2019, Redis Labs - * - * 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_SSL_H -#define __HIREDIS_SSL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the underlying struct for SSL in ssl.h, which is not included to - * keep build dependencies short here. - */ -struct ssl_st; - -/* A wrapper around OpenSSL SSL_CTX to allow easy SSL use without directly - * calling OpenSSL. - */ -typedef struct redisSSLContext redisSSLContext; - -/** - * Initialization errors that redisCreateSSLContext() may return. - */ - -typedef enum { - REDIS_SSL_CTX_NONE = 0, /* No Error */ - REDIS_SSL_CTX_CREATE_FAILED, /* Failed to create OpenSSL SSL_CTX */ - REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */ - REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */ - REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ - REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */ -} redisSSLContextError; - -/** - * Return the error message corresponding with the specified error code. - */ - -const char *redisSSLContextGetError(redisSSLContextError error); - -/** - * Helper function to initialize the OpenSSL library. - * - * OpenSSL requires one-time initialization before it can be used. Callers should - * call this function only once, and only if OpenSSL is not directly initialized - * elsewhere. - */ -int redisInitOpenSSL(void); - -/** - * Helper function to initialize an OpenSSL context that can be used - * to initiate SSL connections. - * - * cacert_filename is an optional name of a CA certificate/bundle file to load - * and use for validation. - * - * capath is an optional directory path where trusted CA certificate files are - * stored in an OpenSSL-compatible structure. - * - * cert_filename and private_key_filename are optional names of a client side - * certificate and private key files to use for authentication. They need to - * be both specified or omitted. - * - * server_name is an optional and will be used as a server name indication - * (SNI) TLS extension. - * - * If error is non-null, it will be populated in case the context creation fails - * (returning a NULL). - */ - -redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath, - const char *cert_filename, const char *private_key_filename, - const char *server_name, redisSSLContextError *error); - -/** - * Free a previously created OpenSSL context. - */ -void redisFreeSSLContext(redisSSLContext *redis_ssl_ctx); - -/** - * Initiate SSL on an existing redisContext. - * - * This is similar to redisInitiateSSL() but does not require the caller - * to directly interact with OpenSSL, and instead uses a redisSSLContext - * previously created using redisCreateSSLContext(). - */ - -int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx); - -/** - * Initiate SSL/TLS negotiation on a provided OpenSSL SSL object. - */ - -int redisInitiateSSL(redisContext *c, struct ssl_st *ssl); - -#ifdef __cplusplus -} -#endif - -#endif /* __HIREDIS_SSL_H */ diff --git a/ext/hiredis-1.0.2/include/hiredis/net.h b/ext/hiredis-1.0.2/include/hiredis/net.h deleted file mode 100644 index 9f43283a..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/net.h +++ /dev/null @@ -1,56 +0,0 @@ -/* 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" - -void redisNetClose(redisContext *c); -ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap); -ssize_t redisNetWrite(redisContext *c); - -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); -int redisCheckConnectDone(redisContext *c, int *completed); - -int redisSetTcpNoDelay(redisContext *c); - -#endif diff --git a/ext/hiredis-1.0.2/include/hiredis/read.h b/ext/hiredis-1.0.2/include/hiredis/read.h deleted file mode 100644 index 2d74d77a..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/read.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 occurred. 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_TIMEOUT 6 /* Timed out */ -#define REDIS_ERR_OTHER 2 /* Everything else... */ - -#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_REPLY_DOUBLE 7 -#define REDIS_REPLY_BOOL 8 -#define REDIS_REPLY_MAP 9 -#define REDIS_REPLY_SET 10 -#define REDIS_REPLY_ATTR 11 -#define REDIS_REPLY_PUSH 12 -#define REDIS_REPLY_BIGNUM 13 -#define REDIS_REPLY_VERB 14 - -/* Default max unused reader buffer. */ -#define REDIS_READER_MAX_BUF (1024*16) - -/* Default multi-bulk element limit */ -#define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1) - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct redisReadTask { - int type; - long long 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*, size_t); - void *(*createInteger)(const redisReadTask*, long long); - void *(*createDouble)(const redisReadTask*, double, char*, size_t); - void *(*createNil)(const redisReadTask*); - void *(*createBool)(const redisReadTask*, int); - 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 */ - long long maxelements; /* Max multi-bulk elements */ - - redisReadTask **task; - int tasks; - - 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); - -#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/hiredis-1.0.2/include/hiredis/sds.h b/ext/hiredis-1.0.2/include/hiredis/sds.h deleted file mode 100644 index eda8833b..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/sds.h +++ /dev/null @@ -1,278 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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) -#ifdef _MSC_VER -#define __attribute__(x) -typedef long long ssize_t; -#define SSIZE_MAX (LLONG_MAX >> 1) -#endif - -#include -#include -#include - -typedef char *sds; - -/* Note: sdshdr5 is never used, we just access the flags byte directly. - * However is here to document the layout of type 5 SDS strings. */ -struct __attribute__ ((__packed__)) sdshdr5 { - unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr8 { - uint8_t len; /* used */ - uint8_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr16 { - uint16_t len; /* used */ - uint16_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr32 { - uint32_t len; /* used */ - uint32_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr64 { - uint64_t len; /* used */ - uint64_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; - -#define SDS_TYPE_5 0 -#define SDS_TYPE_8 1 -#define SDS_TYPE_16 2 -#define SDS_TYPE_32 3 -#define SDS_TYPE_64 4 -#define SDS_TYPE_MASK 7 -#define SDS_TYPE_BITS 3 -#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); -#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) -#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) - -static inline size_t sdslen(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->len; - case SDS_TYPE_16: - return SDS_HDR(16,s)->len; - case SDS_TYPE_32: - return SDS_HDR(32,s)->len; - case SDS_TYPE_64: - return SDS_HDR(64,s)->len; - } - return 0; -} - -static inline size_t sdsavail(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - return 0; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - return sh->alloc - sh->len; - } - } - return 0; -} - -static inline void sdssetlen(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - *fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS)); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len = (uint8_t)newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len = (uint16_t)newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len = (uint32_t)newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len = (uint64_t)newlen; - break; - } -} - -static inline void sdsinclen(sds s, size_t inc) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len += (uint8_t)inc; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len += (uint16_t)inc; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len += (uint32_t)inc; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len += (uint64_t)inc; - break; - } -} - -/* sdsalloc() = sdsavail() + sdslen() */ -static inline size_t sdsalloc(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->alloc; - case SDS_TYPE_16: - return SDS_HDR(16,s)->alloc; - case SDS_TYPE_32: - return SDS_HDR(32,s)->alloc; - case SDS_TYPE_64: - return SDS_HDR(64,s)->alloc; - } - return 0; -} - -static inline void sdssetalloc(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - /* Nothing to do, this type has no total allocation info. */ - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->alloc = (uint8_t)newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->alloc = (uint16_t)newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->alloc = (uint32_t)newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->alloc = (uint64_t)newlen; - break; - } -} - -sds sdsnewlen(const void *init, size_t initlen); -sds sdsnew(const char *init); -sds sdsempty(void); -sds sdsdup(const sds s); -void sdsfree(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, ...); -sds sdstrim(sds s, const char *cset); -int sdsrange(sds s, ssize_t start, ssize_t 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); -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); -void *sdsAllocPtr(sds s); - -/* Export the allocator used by SDS to the program using SDS. - * Sometimes the program SDS is linked to, may use a different set of - * allocators, but may want to allocate or free things that SDS will - * respectively free or allocate. */ -void *sds_malloc(size_t size); -void *sds_realloc(void *ptr, size_t size); -void sds_free(void *ptr); - -#ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); -#endif - -#endif diff --git a/ext/hiredis-1.0.2/include/hiredis/sdsalloc.h b/ext/hiredis-1.0.2/include/hiredis/sdsalloc.h deleted file mode 100644 index 5538dd94..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/sdsalloc.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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. - */ - -/* SDS allocator selection. - * - * This file is used in order to change the SDS allocator at compile time. - * Just define the following defines to what you want to use. Also add - * the include of your alternate allocator if needed (not needed in order - * to use the default libc allocator). */ - -#include "alloc.h" - -#define s_malloc hi_malloc -#define s_realloc hi_realloc -#define s_free hi_free diff --git a/ext/hiredis-1.0.2/include/hiredis/sockcompat.h b/ext/hiredis-1.0.2/include/hiredis/sockcompat.h deleted file mode 100644 index 85810e84..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/sockcompat.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, Marcus Geelnard - * - * 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 __SOCKCOMPAT_H -#define __SOCKCOMPAT_H - -#ifndef _WIN32 -/* For POSIX systems we use the standard BSD socket API. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#else -/* For Windows we use winsock. */ -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */ -#include -#include -#include -#include - -#ifdef _MSC_VER -typedef long long ssize_t; -#endif - -/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */ -int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); -const char *win32_gai_strerror(int errcode); -void win32_freeaddrinfo(struct addrinfo *res); -SOCKET win32_socket(int domain, int type, int protocol); -int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp); -int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen); -int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen); -int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen); -int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen); -int win32_close(SOCKET fd); -ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags); -ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags); -typedef ULONG nfds_t; -int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout); - -#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION -#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res) -#undef gai_strerror -#define gai_strerror(errcode) win32_gai_strerror(errcode) -#define freeaddrinfo(res) win32_freeaddrinfo(res) -#define socket(domain, type, protocol) win32_socket(domain, type, protocol) -#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp) -#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen) -#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen) -#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen) -#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen) -#define close(fd) win32_close(fd) -#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags) -#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags) -#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout) -#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */ -#endif /* _WIN32 */ - -#endif /* __SOCKCOMPAT_H */ diff --git a/ext/hiredis-1.0.2/include/hiredis/win32.h b/ext/hiredis-1.0.2/include/hiredis/win32.h deleted file mode 100644 index 04289c69..00000000 --- a/ext/hiredis-1.0.2/include/hiredis/win32.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _WIN32_HELPER_INCLUDE -#define _WIN32_HELPER_INCLUDE -#ifdef _MSC_VER - -#include /* for struct timeval */ - -#ifndef inline -#define inline __inline -#endif - -#ifndef strcasecmp -#define strcasecmp stricmp -#endif - -#ifndef strncasecmp -#define strncasecmp strnicmp -#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 /* _MSC_VER */ - -#ifdef _WIN32 -#define strerror_r(errno,buf,len) strerror_s(buf,len,errno) -#endif /* _WIN32 */ - -#endif /* _WIN32_HELPER_INCLUDE */ diff --git a/ext/hiredis-1.0.2/lib/ubuntu22.04/amd64/libhiredis.a b/ext/hiredis-1.0.2/lib/ubuntu22.04/amd64/libhiredis.a deleted file mode 100644 index af1314f0..00000000 Binary files a/ext/hiredis-1.0.2/lib/ubuntu22.04/amd64/libhiredis.a and /dev/null differ diff --git a/ext/hiredis-1.0.2/lib/ubuntu22.04/arm64/libhiredis.a b/ext/hiredis-1.0.2/lib/ubuntu22.04/arm64/libhiredis.a deleted file mode 100644 index 081c9270..00000000 Binary files a/ext/hiredis-1.0.2/lib/ubuntu22.04/arm64/libhiredis.a and /dev/null differ diff --git a/ext/hiredis-1.0.2/net.c b/ext/hiredis-1.0.2/net.c deleted file mode 100644 index c6b0e5d8..00000000 --- a/ext/hiredis-1.0.2/net.c +++ /dev/null @@ -1,612 +0,0 @@ -/* 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 "net.h" -#include "sds.h" -#include "sockcompat.h" -#include "win32.h" - -/* Defined in hiredis.c */ -void __redisSetError(redisContext *c, int type, const char *str); - -void redisNetClose(redisContext *c) { - if (c && c->fd != REDIS_INVALID_FD) { - close(c->fd); - c->fd = REDIS_INVALID_FD; - } -} - -ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) { - ssize_t nread = recv(c->fd, buf, bufcap, 0); - if (nread == -1) { - if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { - /* Try again later */ - return 0; - } else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) { - /* especially in windows */ - __redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout"); - return -1; - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } else if (nread == 0) { - __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection"); - return -1; - } else { - return nread; - } -} - -ssize_t redisNetWrite(redisContext *c) { - ssize_t nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0); - if (nwritten < 0) { - if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { - /* Try again later */ - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } - return nwritten; -} - -static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) { - int errorno = errno; /* snprintf() may change errno */ - char buf[128] = { 0 }; - size_t len = 0; - - if (prefix != NULL) - len = snprintf(buf,sizeof(buf),"%s: ",prefix); - strerror_r(errorno, (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); - redisNetClose(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -static int redisCreateSocket(redisContext *c, int type) { - redisFD s; - if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) { - __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) { -#ifndef _WIN32 - 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)"); - redisNetClose(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)"); - redisNetClose(c); - return REDIS_ERR; - } -#else - u_long mode = blocking ? 0 : 1; - if (ioctl(c->fd, FIONBIO, &mode) == -1) { - __redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)"); - redisNetClose(c); - return REDIS_ERR; - } -#endif /* _WIN32 */ - return REDIS_OK; -} - -int redisKeepAlive(redisContext *c, int interval) { - int val = 1; - redisFD 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; - -#if defined(__APPLE__) && defined(__MACH__) - 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__) - 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; -} - -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)"); - redisNetClose(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) - -static int redisContextTimeoutMsec(redisContext *c, long *result) -{ - const struct timeval *timeout = c->connect_timeout; - long msec = -1; - - /* Only use timeout when not NULL. */ - if (timeout != NULL) { - if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { - *result = msec; - return REDIS_ERR; - } - - msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000); - - if (msec < 0 || msec > INT_MAX) { - msec = INT_MAX; - } - } - - *result = msec; - return REDIS_OK; -} - -static int redisContextWaitReady(redisContext *c, long msec) { - struct pollfd wfd[1]; - - wfd[0].fd = c->fd; - wfd[0].events = POLLOUT; - - if (errno == EINPROGRESS) { - int res; - - if ((res = poll(wfd, 1, msec)) == -1) { - __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)"); - redisNetClose(c); - return REDIS_ERR; - } else if (res == 0) { - errno = ETIMEDOUT; - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisNetClose(c); - return REDIS_ERR; - } - - if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) { - redisCheckSocketError(c); - return REDIS_ERR; - } - - return REDIS_OK; - } - - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisNetClose(c); - return REDIS_ERR; -} - -int redisCheckConnectDone(redisContext *c, int *completed) { - int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen); - if (rc == 0) { - *completed = 1; - return REDIS_OK; - } - switch (errno) { - case EISCONN: - *completed = 1; - return REDIS_OK; - case EALREADY: - case EINPROGRESS: - case EWOULDBLOCK: - *completed = 0; - return REDIS_OK; - default: - return REDIS_ERR; - } -} - -int redisCheckSocketError(redisContext *c) { - int err = 0, errno_saved = errno; - 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 == 0) { - err = errno_saved; - } - - if (err) { - errno = err; - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - - return REDIS_OK; -} - -int redisContextSetTimeout(redisContext *c, const struct timeval tv) { - const void *to_ptr = &tv; - size_t to_sz = sizeof(tv); - - if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)"); - return REDIS_ERR; - } - if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)"); - return REDIS_ERR; - } - return REDIS_OK; -} - -int redisContextUpdateConnectTimeout(redisContext *c, const struct timeval *timeout) { - /* Same timeval struct, short circuit */ - if (c->connect_timeout == timeout) - return REDIS_OK; - - /* Allocate context timeval if we need to */ - if (c->connect_timeout == NULL) { - c->connect_timeout = hi_malloc(sizeof(*c->connect_timeout)); - if (c->connect_timeout == NULL) - return REDIS_ERR; - } - - memcpy(c->connect_timeout, timeout, sizeof(*c->connect_timeout)); - return REDIS_OK; -} - -int redisContextUpdateCommandTimeout(redisContext *c, const struct timeval *timeout) { - /* Same timeval struct, short circuit */ - if (c->command_timeout == timeout) - return REDIS_OK; - - /* Allocate context timeval if we need to */ - if (c->command_timeout == NULL) { - c->command_timeout = hi_malloc(sizeof(*c->command_timeout)); - if (c->command_timeout == NULL) - return REDIS_ERR; - } - - memcpy(c->command_timeout, timeout, sizeof(*c->command_timeout)); - return REDIS_OK; -} - -static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout, - const char *source_addr) { - redisFD s; - int 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; - long timeout_msec = -1; - - servinfo = NULL; - 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) { - hi_free(c->tcp.host); - - c->tcp.host = hi_strdup(addr); - if (c->tcp.host == NULL) - goto oom; - } - - if (timeout) { - if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR) - goto oom; - } else { - hi_free(c->connect_timeout); - c->connect_timeout = NULL; - } - - if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) { - __redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified"); - goto error; - } - - if (source_addr == NULL) { - hi_free(c->tcp.source_addr); - c->tcp.source_addr = NULL; - } else if (c->tcp.source_addr != source_addr) { - hi_free(c->tcp.source_addr); - c->tcp.source_addr = hi_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)) == REDIS_INVALID_FD) - 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) { - freeaddrinfo(bservinfo); - 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; - } - } - - /* For repeat connection */ - hi_free(c->saddr); - c->saddr = hi_malloc(p->ai_addrlen); - if (c->saddr == NULL) - goto oom; - - memcpy(c->saddr, p->ai_addr, p->ai_addrlen); - c->addrlen = p->ai_addrlen; - - if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { - if (errno == EHOSTUNREACH) { - redisNetClose(c); - continue; - } else if (errno == EINPROGRESS) { - if (blocking) { - goto wait_for_ready; - } - /* This is ok. - * Note that even when it's in blocking mode, we unset blocking - * for `connect()` - */ - } else if (errno == EADDRNOTAVAIL && reuseaddr) { - if (++reuses >= REDIS_CONNECT_RETRIES) { - goto error; - } else { - redisNetClose(c); - goto addrretry; - } - } else { - wait_for_ready: - if (redisContextWaitReady(c,timeout_msec) != REDIS_OK) - goto error; - if (redisSetTcpNoDelay(c) != REDIS_OK) - goto error; - } - } - if (blocking && redisSetBlocking(c,1) != 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; - } - -oom: - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); -error: - rv = REDIS_ERR; -end: - if(servinfo) { - 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) { -#ifndef _WIN32 - int blocking = (c->flags & REDIS_BLOCK); - struct sockaddr_un *sa; - long timeout_msec = -1; - - if (redisCreateSocket(c,AF_UNIX) < 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) { - hi_free(c->unix_sock.path); - - c->unix_sock.path = hi_strdup(path); - if (c->unix_sock.path == NULL) - goto oom; - } - - if (timeout) { - if (redisContextUpdateConnectTimeout(c, timeout) == REDIS_ERR) - goto oom; - } else { - hi_free(c->connect_timeout); - c->connect_timeout = NULL; - } - - if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK) - return REDIS_ERR; - - /* Don't leak sockaddr if we're reconnecting */ - if (c->saddr) hi_free(c->saddr); - - sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un))); - if (sa == NULL) - goto oom; - - c->addrlen = sizeof(struct sockaddr_un); - sa->sun_family = AF_UNIX; - 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,timeout_msec) != 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; -#else - /* We currently do not support Unix sockets for Windows. */ - /* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */ - errno = EPROTONOSUPPORT; - return REDIS_ERR; -#endif /* _WIN32 */ -oom: - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; -} diff --git a/ext/hiredis-1.0.2/net.h b/ext/hiredis-1.0.2/net.h deleted file mode 100644 index 9f43283a..00000000 --- a/ext/hiredis-1.0.2/net.h +++ /dev/null @@ -1,56 +0,0 @@ -/* 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" - -void redisNetClose(redisContext *c); -ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap); -ssize_t redisNetWrite(redisContext *c); - -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); -int redisCheckConnectDone(redisContext *c, int *completed); - -int redisSetTcpNoDelay(redisContext *c); - -#endif diff --git a/ext/hiredis-1.0.2/read.c b/ext/hiredis-1.0.2/read.c deleted file mode 100644 index 09524692..00000000 --- a/ext/hiredis-1.0.2/read.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - * 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 -#include -#endif -#include -#include -#include -#include -#include - -#include "alloc.h" -#include "read.h" -#include "sds.h" -#include "win32.h" - -/* Initial size of our nested reply stack and how much we grow it when needd */ -#define REDIS_READER_STACK_SIZE 9 - -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. */ - 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 (pos==_len) { - /* Not found. */ - return NULL; - } else { - if (s[pos+1] == '\n') { - /* Found. */ - return s+pos; - } else { - /* Continue searching. */ - pos++; - } - } - } - return NULL; -} - -/* Convert a string into a long long. Returns REDIS_OK if the string could be - * parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value - * will be set to the parsed value when appropriate. - * - * Note that this function demands that the string strictly represents - * a long long: no spaces or other characters before or after the string - * representing the number are accepted, nor zeroes at the start if not - * for the string "0" representing the zero number. - * - * Because of its strictness, it is safe to use this function to check if - * you can convert a string into a long long, and obtain back the string - * from the number without any loss in the string representation. */ -static int string2ll(const char *s, size_t slen, long long *value) { - const char *p = s; - size_t plen = 0; - int negative = 0; - unsigned long long v; - - if (plen == slen) - return REDIS_ERR; - - /* Special case: first and only digit is 0. */ - if (slen == 1 && p[0] == '0') { - if (value != NULL) *value = 0; - return REDIS_OK; - } - - if (p[0] == '-') { - negative = 1; - p++; plen++; - - /* Abort on only a negative sign. */ - if (plen == slen) - return REDIS_ERR; - } - - /* First digit should be 1-9, otherwise the string should just be 0. */ - if (p[0] >= '1' && p[0] <= '9') { - v = p[0]-'0'; - p++; plen++; - } else if (p[0] == '0' && slen == 1) { - *value = 0; - return REDIS_OK; - } else { - return REDIS_ERR; - } - - while (plen < slen && p[0] >= '0' && p[0] <= '9') { - if (v > (ULLONG_MAX / 10)) /* Overflow. */ - return REDIS_ERR; - v *= 10; - - if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */ - return REDIS_ERR; - v += p[0]-'0'; - - p++; plen++; - } - - /* Return if not all bytes were used. */ - if (plen < slen) - return REDIS_ERR; - - if (negative) { - if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */ - return REDIS_ERR; - if (value != NULL) *value = -v; - } else { - if (v > LLONG_MAX) /* Overflow. */ - return REDIS_ERR; - if (value != NULL) *value = v; - } - return REDIS_OK; -} - -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->task[r->ridx]; - prv = r->task[r->ridx-1]; - assert(prv->type == REDIS_REPLY_ARRAY || - prv->type == REDIS_REPLY_MAP || - prv->type == REDIS_REPLY_SET || - prv->type == REDIS_REPLY_PUSH); - 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->task[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) { - long long v; - if (string2ll(p, len, &v) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad integer value"); - return REDIS_ERR; - } - obj = r->fn->createInteger(cur,v); - } else { - obj = (void*)REDIS_REPLY_INTEGER; - } - } else if (cur->type == REDIS_REPLY_DOUBLE) { - if (r->fn && r->fn->createDouble) { - char buf[326], *eptr; - double d; - - if ((size_t)len >= sizeof(buf)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Double value is too large"); - return REDIS_ERR; - } - - memcpy(buf,p,len); - buf[len] = '\0'; - - if (strcasecmp(buf,",inf") == 0) { - d = INFINITY; /* Positive infinite. */ - } else if (strcasecmp(buf,",-inf") == 0) { - d = -INFINITY; /* Negative infinite. */ - } else { - d = strtod((char*)buf,&eptr); - if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad double value"); - return REDIS_ERR; - } - } - obj = r->fn->createDouble(cur,d,buf,len); - } else { - obj = (void*)REDIS_REPLY_DOUBLE; - } - } else if (cur->type == REDIS_REPLY_NIL) { - if (r->fn && r->fn->createNil) - obj = r->fn->createNil(cur); - else - obj = (void*)REDIS_REPLY_NIL; - } else if (cur->type == REDIS_REPLY_BOOL) { - int bval = p[0] == 't' || p[0] == 'T'; - if (r->fn && r->fn->createBool) - obj = r->fn->createBool(cur,bval); - else - obj = (void*)REDIS_REPLY_BOOL; - } 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->task[r->ridx]; - void *obj = NULL; - char *p, *s; - long 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 */ - - if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad bulk string length"); - return REDIS_ERR; - } - - if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bulk string length out of range"); - return REDIS_ERR; - } - - if (len == -1) { - /* 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 ((cur->type == REDIS_REPLY_VERB && len < 4) || - (cur->type == REDIS_REPLY_VERB && s[5] != ':')) - { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Verbatim string 4 bytes of content type are " - "missing or incorrectly encoded."); - return REDIS_ERR; - } - if (r->fn && r->fn->createString) - obj = r->fn->createString(cur,s+2,len); - else - obj = (void*)(long)cur->type; - 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 redisReaderGrow(redisReader *r) { - redisReadTask **aux; - int newlen; - - /* Grow our stack size */ - newlen = r->tasks + REDIS_READER_STACK_SIZE; - aux = hi_realloc(r->task, sizeof(*r->task) * newlen); - if (aux == NULL) - goto oom; - - r->task = aux; - - /* Allocate new tasks */ - for (; r->tasks < newlen; r->tasks++) { - r->task[r->tasks] = hi_calloc(1, sizeof(**r->task)); - if (r->task[r->tasks] == NULL) - goto oom; - } - - return REDIS_OK; -oom: - __redisReaderSetErrorOOM(r); - return REDIS_ERR; -} - -/* Process the array, map and set types. */ -static int processAggregateItem(redisReader *r) { - redisReadTask *cur = r->task[r->ridx]; - void *obj; - char *p; - long long elements; - int root = 0, len; - - /* Set error for nested multi bulks with depth > 7 */ - if (r->ridx == r->tasks - 1) { - if (redisReaderGrow(r) == REDIS_ERR) - return REDIS_ERR; - } - - if ((p = readLine(r,&len)) != NULL) { - if (string2ll(p, len, &elements) == REDIS_ERR) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Bad multi-bulk length"); - return REDIS_ERR; - } - - root = (r->ridx == 0); - - if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX) || - (r->maxelements > 0 && elements > r->maxelements)) - { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "Multi-bulk length out of range"); - return REDIS_ERR; - } - - 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 (cur->type == REDIS_REPLY_MAP) elements *= 2; - - if (r->fn && r->fn->createArray) - obj = r->fn->createArray(cur,elements); - else - obj = (void*)(long)cur->type; - - 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->task[r->ridx]->type = -1; - r->task[r->ridx]->elements = -1; - r->task[r->ridx]->idx = 0; - r->task[r->ridx]->obj = NULL; - r->task[r->ridx]->parent = cur; - r->task[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->task[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_DOUBLE; - break; - case '_': - cur->type = REDIS_REPLY_NIL; - break; - case '$': - cur->type = REDIS_REPLY_STRING; - break; - case '*': - cur->type = REDIS_REPLY_ARRAY; - break; - case '%': - cur->type = REDIS_REPLY_MAP; - break; - case '~': - cur->type = REDIS_REPLY_SET; - break; - case '#': - cur->type = REDIS_REPLY_BOOL; - break; - case '=': - cur->type = REDIS_REPLY_VERB; - break; - case '>': - cur->type = REDIS_REPLY_PUSH; - 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: - case REDIS_REPLY_DOUBLE: - case REDIS_REPLY_NIL: - case REDIS_REPLY_BOOL: - return processLineItem(r); - case REDIS_REPLY_STRING: - case REDIS_REPLY_VERB: - return processBulkItem(r); - case REDIS_REPLY_ARRAY: - case REDIS_REPLY_MAP: - case REDIS_REPLY_SET: - case REDIS_REPLY_PUSH: - return processAggregateItem(r); - default: - assert(NULL); - return REDIS_ERR; /* Avoid warning. */ - } -} - -redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { - redisReader *r; - - r = hi_calloc(1,sizeof(redisReader)); - if (r == NULL) - return NULL; - - r->buf = sdsempty(); - if (r->buf == NULL) - goto oom; - - r->task = hi_calloc(REDIS_READER_STACK_SIZE, sizeof(*r->task)); - if (r->task == NULL) - goto oom; - - for (; r->tasks < REDIS_READER_STACK_SIZE; r->tasks++) { - r->task[r->tasks] = hi_calloc(1, sizeof(**r->task)); - if (r->task[r->tasks] == NULL) - goto oom; - } - - r->fn = fn; - r->maxbuf = REDIS_READER_MAX_BUF; - r->maxelements = REDIS_READER_MAX_ARRAY_ELEMENTS; - r->ridx = -1; - - return r; -oom: - redisReaderFree(r); - return NULL; -} - -void redisReaderFree(redisReader *r) { - if (r == NULL) - return; - - if (r->reply != NULL && r->fn && r->fn->freeObject) - r->fn->freeObject(r->reply); - - if (r->task) { - /* We know r->task[i] is allocated if i < r->tasks */ - for (int i = 0; i < r->tasks; i++) { - hi_free(r->task[i]); - } - - hi_free(r->task); - } - - sdsfree(r->buf); - hi_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(); - if (r->buf == 0) goto oom; - - r->pos = 0; - } - - newbuf = sdscatlen(r->buf,buf,len); - if (newbuf == NULL) goto oom; - - r->buf = newbuf; - r->len = sdslen(r->buf); - } - - return REDIS_OK; -oom: - __redisReaderSetErrorOOM(r); - return REDIS_ERR; -} - -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->task[0]->type = -1; - r->task[0]->elements = -1; - r->task[0]->idx = -1; - r->task[0]->obj = NULL; - r->task[0]->parent = NULL; - r->task[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) { - if (sdsrange(r->buf,r->pos,-1) < 0) return REDIS_ERR; - 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; - } else if (r->reply != NULL && r->fn && r->fn->freeObject) { - r->fn->freeObject(r->reply); - } - r->reply = NULL; - } - return REDIS_OK; -} diff --git a/ext/hiredis-1.0.2/read.h b/ext/hiredis-1.0.2/read.h deleted file mode 100644 index 2d74d77a..00000000 --- a/ext/hiredis-1.0.2/read.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 occurred. 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_TIMEOUT 6 /* Timed out */ -#define REDIS_ERR_OTHER 2 /* Everything else... */ - -#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_REPLY_DOUBLE 7 -#define REDIS_REPLY_BOOL 8 -#define REDIS_REPLY_MAP 9 -#define REDIS_REPLY_SET 10 -#define REDIS_REPLY_ATTR 11 -#define REDIS_REPLY_PUSH 12 -#define REDIS_REPLY_BIGNUM 13 -#define REDIS_REPLY_VERB 14 - -/* Default max unused reader buffer. */ -#define REDIS_READER_MAX_BUF (1024*16) - -/* Default multi-bulk element limit */ -#define REDIS_READER_MAX_ARRAY_ELEMENTS ((1LL<<32) - 1) - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct redisReadTask { - int type; - long long 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*, size_t); - void *(*createInteger)(const redisReadTask*, long long); - void *(*createDouble)(const redisReadTask*, double, char*, size_t); - void *(*createNil)(const redisReadTask*); - void *(*createBool)(const redisReadTask*, int); - 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 */ - long long maxelements; /* Max multi-bulk elements */ - - redisReadTask **task; - int tasks; - - 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); - -#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/hiredis-1.0.2/sds.c b/ext/hiredis-1.0.2/sds.c deleted file mode 100644 index 49d2096b..00000000 --- a/ext/hiredis-1.0.2/sds.c +++ /dev/null @@ -1,1289 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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 "sds.h" -#include "sdsalloc.h" - -static inline int sdsHdrSize(char type) { - switch(type&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return sizeof(struct sdshdr5); - case SDS_TYPE_8: - return sizeof(struct sdshdr8); - case SDS_TYPE_16: - return sizeof(struct sdshdr16); - case SDS_TYPE_32: - return sizeof(struct sdshdr32); - case SDS_TYPE_64: - return sizeof(struct sdshdr64); - } - return 0; -} - -static inline char sdsReqType(size_t string_size) { - if (string_size < 32) - return SDS_TYPE_5; - if (string_size < 0xff) - return SDS_TYPE_8; - if (string_size < 0xffff) - return SDS_TYPE_16; - if (string_size < 0xffffffff) - return SDS_TYPE_32; - return SDS_TYPE_64; -} - -/* 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) { - void *sh; - sds s; - char type = sdsReqType(initlen); - /* Empty strings are usually created in order to append. Use type 8 - * since type 5 is not good at this. */ - if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; - int hdrlen = sdsHdrSize(type); - unsigned char *fp; /* flags pointer. */ - - sh = s_malloc(hdrlen+initlen+1); - if (sh == NULL) return NULL; - if (!init) - memset(sh, 0, hdrlen+initlen+1); - s = (char*)sh+hdrlen; - fp = ((unsigned char*)s)-1; - switch(type) { - case SDS_TYPE_5: { - *fp = type | (initlen << SDS_TYPE_BITS); - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - } - if (initlen && init) - memcpy(s, init, initlen); - s[initlen] = '\0'; - return s; -} - -/* 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 terminated 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; - s_free((char*)s-sdsHdrSize(s[-1])); -} - -/* 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) { - int reallen = strlen(s); - sdssetlen(s, reallen); -} - -/* Modify an sds string in-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) { - sdssetlen(s, 0); - s[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) { - void *sh, *newsh; - size_t avail = sdsavail(s); - size_t len, newlen; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - - /* Return ASAP if there is enough space left. */ - if (avail >= addlen) return s; - - len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - newlen = (len+addlen); - if (newlen < SDS_MAX_PREALLOC) - newlen *= 2; - else - newlen += SDS_MAX_PREALLOC; - - type = sdsReqType(newlen); - - /* Don't use type 5: the user is appending to the string and type 5 is - * not able to remember empty space, so sdsMakeRoomFor() must be called - * at every appending operation. */ - if (type == SDS_TYPE_5) type = SDS_TYPE_8; - - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+newlen+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - /* Since the header size changes, need to move the string forward, - * and can't use realloc */ - newsh = s_malloc(hdrlen+newlen+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, newlen); - return s; -} - -/* 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) { - void *sh, *newsh; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - size_t len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - - type = sdsReqType(len); - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+len+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - newsh = s_malloc(hdrlen+len+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, len); - return s; -} - -/* 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) { - size_t alloc = sdsalloc(s); - return sdsHdrSize(s[-1])+alloc+1; -} - -/* Return the pointer of the actual SDS allocation (normally SDS strings - * are referenced by the start of the string buffer). */ -void *sdsAllocPtr(sds s) { - return (void*) (s-sdsHdrSize(s[-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) { - unsigned char flags = s[-1]; - size_t len; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char oldlen = SDS_TYPE_5_LEN(flags); - assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr))); - *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS); - len = oldlen+incr; - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr))); - len = (sh->len += incr); - break; - } - default: len = 0; /* Just to avoid compilation warnings. */ - } - s[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) { - size_t curlen = sdslen(s); - - if (len <= curlen) return s; - s = sdsMakeRoomFor(s,len-curlen); - if (s == NULL) return NULL; - - /* Make sure added region doesn't contain garbage */ - memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ - sdssetlen(s, 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) { - size_t curlen = sdslen(s); - - s = sdsMakeRoomFor(s,len); - if (s == NULL) return NULL; - memcpy(s+curlen, t, len); - sdssetlen(s, curlen+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) { - if (sdsalloc(s) < len) { - s = sdsMakeRoomFor(s,len-sdslen(s)); - if (s == NULL) return NULL; - } - memcpy(s, t, len); - s[len] = '\0'; - sdssetlen(s, 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 length 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; -} - -/* 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[SDS_LLSTR_SIZE]; - int len = sdsll2str(buf,value); - - return sdsnewlen(buf,len); -} - -/* Like sdscatprintf() but gets va_list instead of being variadic. */ -sds sdscatvprintf(sds s, const char *fmt, va_list ap) { - va_list cpy; - char staticbuf[1024], *buf = staticbuf, *t; - size_t buflen = strlen(fmt)*2; - - /* We try to start using a static buffer for speed. - * If not possible we revert to heap allocation. */ - if (buflen > sizeof(staticbuf)) { - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - } else { - buflen = sizeof(staticbuf); - } - - /* Try with buffers two times bigger every time we fail to - * fit the string in the current buffer size. */ - while(1) { - buf[buflen-2] = '\0'; - va_copy(cpy,ap); - vsnprintf(buf, buflen, fmt, cpy); - va_end(cpy); - if (buf[buflen-2] != '\0') { - if (buf != staticbuf) s_free(buf); - buflen *= 2; - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - continue; - } - break; - } - - /* Finally concat the obtained string to the SDS string and return it. */ - t = sdscat(s, buf); - if (buf != staticbuf) s_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) - * %% - Verbatim "%" character. - */ -sds sdscatfmt(sds s, char const *fmt, ...) { - const char *f = fmt; - int i; - va_list ap; - - va_start(ap,fmt); - i = sdslen(s); /* Position of the next byte to write to dest str. */ - while(*f) { - char next, *str; - size_t l; - long long num; - unsigned long long unum; - - /* Make sure there is always space for at least 1 char. */ - if (sdsavail(s)==0) { - s = sdsMakeRoomFor(s,1); - if (s == NULL) goto fmt_error; - } - - 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 (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - if (s == NULL) goto fmt_error; - } - memcpy(s+i,str,l); - sdsinclen(s,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 (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - if (s == NULL) goto fmt_error; - } - memcpy(s+i,buf,l); - sdsinclen(s,l); - i += l; - } - break; - case 'u': - case 'U': - if (next == 'u') - unum = va_arg(ap,unsigned int); - else - unum = va_arg(ap,unsigned long long); - { - char buf[SDS_LLSTR_SIZE]; - l = sdsull2str(buf,unum); - if (sdsavail(s) < l) { - s = sdsMakeRoomFor(s,l); - if (s == NULL) goto fmt_error; - } - memcpy(s+i,buf,l); - sdsinclen(s,l); - i += l; - } - break; - default: /* Handle %% and generally %. */ - s[i++] = next; - sdsinclen(s,1); - break; - } - break; - default: - s[i++] = *f; - sdsinclen(s,1); - break; - } - f++; - } - va_end(ap); - - /* Add null-term */ - s[i] = '\0'; - return s; - -fmt_error: - va_end(ap); - return NULL; -} - -/* 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,"Aa. :"); - * printf("%s\n", s); - * - * Output will be just "Hello World". - */ -sds sdstrim(sds s, const char *cset) { - 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 > sp && strchr(cset, *ep)) ep--; - len = (sp > ep) ? 0 : ((ep-sp)+1); - if (s != sp) memmove(s, sp, len); - s[len] = '\0'; - sdssetlen(s,len); - return s; -} - -/* 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. - * - * Return value: - * -1 (error) if sdslen(s) is larger than maximum positive ssize_t value. - * 0 on success. - * - * Example: - * - * s = sdsnew("Hello World"); - * sdsrange(s,1,-1); => "ello World" - */ -int sdsrange(sds s, ssize_t start, ssize_t end) { - size_t newlen, len = sdslen(s); - if (len > SSIZE_MAX) return -1; - - if (len == 0) return 0; - 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 >= (ssize_t)len) { - newlen = 0; - } else if (end >= (ssize_t)len) { - end = len-1; - newlen = (start > end) ? 0 : (end-start)+1; - } - } else { - start = 0; - } - if (start && newlen) memmove(s, s+start, newlen); - s[newlen] = 0; - sdssetlen(s,newlen); - return 0; -} - -/* 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: - * - * positive if s1 > s2. - * negative 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 = s_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 = s_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]); - s_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]); - s_free(tokens); -} - -/* 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 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' && - isxdigit(*(p+2)) && - isxdigit(*(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 */ - { - char **new_vector = s_realloc(vector,((*argc)+1)*sizeof(char*)); - if (new_vector == NULL) { - s_free(vector); - return NULL; - } - - vector = new_vector; - vector[*argc] = current; - (*argc)++; - current = NULL; - } - } else { - /* Even on empty input string return something not NULL. */ - if (vector == NULL) vector = s_malloc(sizeof(void*)); - return vector; - } - } - -err: - while((*argc)--) - sdsfree(vector[*argc]); - s_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) { - sds join = sdsempty(); - int j; - - for (j = 0; j < argc; j++) { - join = sdscat(join, argv[j]); - if (j != argc-1) join = sdscat(join,sep); - } - 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; -} - -/* Wrappers to the allocators used by SDS. Note that SDS will actually - * just use the macros defined into sdsalloc.h in order to avoid to pay - * the overhead of function calls. Here we define these wrappers only for - * the programs SDS is linked to, if they want to touch the SDS internals - * even if they use a different allocator. */ -void *sds_malloc(size_t size) { return s_malloc(size); } -void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); } -void sds_free(void *ptr) { s_free(ptr); } - -#if defined(SDS_TEST_MAIN) -#include -#include "testhelp.h" -#include "limits.h" - -#define UNUSED(x) (void)(x) -int sdsTest(void) { - { - 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("--"); - x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX); - test_cond("sdscatfmt() seems working in the base case", - sdslen(x) == 60 && - memcmp(x,"--Hello Hi! World -9223372036854775808," - "9223372036854775807--",60) == 0) - printf("[%s]\n",x); - - sdsfree(x); - x = sdsnew("--"); - x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX); - test_cond("sdscatfmt() seems working with unsigned numbers", - sdslen(x) == 35 && - memcmp(x,"--4294967295,18446744073709551615--",35) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," x"); - test_cond("sdstrim() works when all chars match", - sdslen(x) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," "); - test_cond("sdstrim() works when a single char remains", - sdslen(x) == 1 && x[0] == 'x') - - 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) - - { - unsigned int oldfree; - char *p; - int step = 10, j, i; - - sdsfree(x); - sdsfree(y); - x = sdsnew("0"); - test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0); - - /* Run the test a few times in order to hit the first two - * SDS header types. */ - for (i = 0; i < 10; i++) { - int oldlen = sdslen(x); - x = sdsMakeRoomFor(x,step); - int type = x[-1]&SDS_TYPE_MASK; - - test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen); - if (type != SDS_TYPE_5) { - test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step); - oldfree = sdsavail(x); - } - p = x+oldlen; - for (j = 0; j < step; j++) { - p[j] = 'A'+j; - } - sdsIncrLen(x,step); - } - test_cond("sdsMakeRoomFor() content", - memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0); - test_cond("sdsMakeRoomFor() final length",sdslen(x)==101); - - sdsfree(x); - } - } - test_report() - return 0; -} -#endif - -#ifdef SDS_TEST_MAIN -int main(void) { - return sdsTest(); -} -#endif diff --git a/ext/hiredis-1.0.2/sds.h b/ext/hiredis-1.0.2/sds.h deleted file mode 100644 index eda8833b..00000000 --- a/ext/hiredis-1.0.2/sds.h +++ /dev/null @@ -1,278 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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) -#ifdef _MSC_VER -#define __attribute__(x) -typedef long long ssize_t; -#define SSIZE_MAX (LLONG_MAX >> 1) -#endif - -#include -#include -#include - -typedef char *sds; - -/* Note: sdshdr5 is never used, we just access the flags byte directly. - * However is here to document the layout of type 5 SDS strings. */ -struct __attribute__ ((__packed__)) sdshdr5 { - unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr8 { - uint8_t len; /* used */ - uint8_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr16 { - uint16_t len; /* used */ - uint16_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr32 { - uint32_t len; /* used */ - uint32_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr64 { - uint64_t len; /* used */ - uint64_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; - -#define SDS_TYPE_5 0 -#define SDS_TYPE_8 1 -#define SDS_TYPE_16 2 -#define SDS_TYPE_32 3 -#define SDS_TYPE_64 4 -#define SDS_TYPE_MASK 7 -#define SDS_TYPE_BITS 3 -#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); -#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) -#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) - -static inline size_t sdslen(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->len; - case SDS_TYPE_16: - return SDS_HDR(16,s)->len; - case SDS_TYPE_32: - return SDS_HDR(32,s)->len; - case SDS_TYPE_64: - return SDS_HDR(64,s)->len; - } - return 0; -} - -static inline size_t sdsavail(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - return 0; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - return sh->alloc - sh->len; - } - } - return 0; -} - -static inline void sdssetlen(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - *fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS)); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len = (uint8_t)newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len = (uint16_t)newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len = (uint32_t)newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len = (uint64_t)newlen; - break; - } -} - -static inline void sdsinclen(sds s, size_t inc) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len += (uint8_t)inc; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len += (uint16_t)inc; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len += (uint32_t)inc; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len += (uint64_t)inc; - break; - } -} - -/* sdsalloc() = sdsavail() + sdslen() */ -static inline size_t sdsalloc(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->alloc; - case SDS_TYPE_16: - return SDS_HDR(16,s)->alloc; - case SDS_TYPE_32: - return SDS_HDR(32,s)->alloc; - case SDS_TYPE_64: - return SDS_HDR(64,s)->alloc; - } - return 0; -} - -static inline void sdssetalloc(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - /* Nothing to do, this type has no total allocation info. */ - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->alloc = (uint8_t)newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->alloc = (uint16_t)newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->alloc = (uint32_t)newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->alloc = (uint64_t)newlen; - break; - } -} - -sds sdsnewlen(const void *init, size_t initlen); -sds sdsnew(const char *init); -sds sdsempty(void); -sds sdsdup(const sds s); -void sdsfree(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, ...); -sds sdstrim(sds s, const char *cset); -int sdsrange(sds s, ssize_t start, ssize_t 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); -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); -void *sdsAllocPtr(sds s); - -/* Export the allocator used by SDS to the program using SDS. - * Sometimes the program SDS is linked to, may use a different set of - * allocators, but may want to allocate or free things that SDS will - * respectively free or allocate. */ -void *sds_malloc(size_t size); -void *sds_realloc(void *ptr, size_t size); -void sds_free(void *ptr); - -#ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); -#endif - -#endif diff --git a/ext/hiredis-1.0.2/sdsalloc.h b/ext/hiredis-1.0.2/sdsalloc.h deleted file mode 100644 index 5538dd94..00000000 --- a/ext/hiredis-1.0.2/sdsalloc.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * 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. - */ - -/* SDS allocator selection. - * - * This file is used in order to change the SDS allocator at compile time. - * Just define the following defines to what you want to use. Also add - * the include of your alternate allocator if needed (not needed in order - * to use the default libc allocator). */ - -#include "alloc.h" - -#define s_malloc hi_malloc -#define s_realloc hi_realloc -#define s_free hi_free diff --git a/ext/hiredis-1.0.2/sockcompat.c b/ext/hiredis-1.0.2/sockcompat.c deleted file mode 100644 index f99d14b0..00000000 --- a/ext/hiredis-1.0.2/sockcompat.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2019, Marcus Geelnard - * - * 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. - */ - -#define REDIS_SOCKCOMPAT_IMPLEMENTATION -#include "sockcompat.h" - -#ifdef _WIN32 -static int _wsaErrorToErrno(int err) { - switch (err) { - case WSAEWOULDBLOCK: - return EWOULDBLOCK; - case WSAEINPROGRESS: - return EINPROGRESS; - case WSAEALREADY: - return EALREADY; - case WSAENOTSOCK: - return ENOTSOCK; - case WSAEDESTADDRREQ: - return EDESTADDRREQ; - case WSAEMSGSIZE: - return EMSGSIZE; - case WSAEPROTOTYPE: - return EPROTOTYPE; - case WSAENOPROTOOPT: - return ENOPROTOOPT; - case WSAEPROTONOSUPPORT: - return EPROTONOSUPPORT; - case WSAEOPNOTSUPP: - return EOPNOTSUPP; - case WSAEAFNOSUPPORT: - return EAFNOSUPPORT; - case WSAEADDRINUSE: - return EADDRINUSE; - case WSAEADDRNOTAVAIL: - return EADDRNOTAVAIL; - case WSAENETDOWN: - return ENETDOWN; - case WSAENETUNREACH: - return ENETUNREACH; - case WSAENETRESET: - return ENETRESET; - case WSAECONNABORTED: - return ECONNABORTED; - case WSAECONNRESET: - return ECONNRESET; - case WSAENOBUFS: - return ENOBUFS; - case WSAEISCONN: - return EISCONN; - case WSAENOTCONN: - return ENOTCONN; - case WSAETIMEDOUT: - return ETIMEDOUT; - case WSAECONNREFUSED: - return ECONNREFUSED; - case WSAELOOP: - return ELOOP; - case WSAENAMETOOLONG: - return ENAMETOOLONG; - case WSAEHOSTUNREACH: - return EHOSTUNREACH; - case WSAENOTEMPTY: - return ENOTEMPTY; - default: - /* We just return a generic I/O error if we could not find a relevant error. */ - return EIO; - } -} - -static void _updateErrno(int success) { - errno = success ? 0 : _wsaErrorToErrno(WSAGetLastError()); -} - -static int _initWinsock() { - static int s_initialized = 0; - if (!s_initialized) { - static WSADATA wsadata; - int err = WSAStartup(MAKEWORD(2,2), &wsadata); - if (err != 0) { - errno = _wsaErrorToErrno(err); - return 0; - } - s_initialized = 1; - } - return 1; -} - -int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { - /* Note: This function is likely to be called before other functions, so run init here. */ - if (!_initWinsock()) { - return EAI_FAIL; - } - - switch (getaddrinfo(node, service, hints, res)) { - case 0: return 0; - case WSATRY_AGAIN: return EAI_AGAIN; - case WSAEINVAL: return EAI_BADFLAGS; - case WSAEAFNOSUPPORT: return EAI_FAMILY; - case WSA_NOT_ENOUGH_MEMORY: return EAI_MEMORY; - case WSAHOST_NOT_FOUND: return EAI_NONAME; - case WSATYPE_NOT_FOUND: return EAI_SERVICE; - case WSAESOCKTNOSUPPORT: return EAI_SOCKTYPE; - default: return EAI_FAIL; /* Including WSANO_RECOVERY */ - } -} - -const char *win32_gai_strerror(int errcode) { - switch (errcode) { - case 0: errcode = 0; break; - case EAI_AGAIN: errcode = WSATRY_AGAIN; break; - case EAI_BADFLAGS: errcode = WSAEINVAL; break; - case EAI_FAMILY: errcode = WSAEAFNOSUPPORT; break; - case EAI_MEMORY: errcode = WSA_NOT_ENOUGH_MEMORY; break; - case EAI_NONAME: errcode = WSAHOST_NOT_FOUND; break; - case EAI_SERVICE: errcode = WSATYPE_NOT_FOUND; break; - case EAI_SOCKTYPE: errcode = WSAESOCKTNOSUPPORT; break; - default: errcode = WSANO_RECOVERY; break; /* Including EAI_FAIL */ - } - return gai_strerror(errcode); -} - -void win32_freeaddrinfo(struct addrinfo *res) { - freeaddrinfo(res); -} - -SOCKET win32_socket(int domain, int type, int protocol) { - SOCKET s; - - /* Note: This function is likely to be called before other functions, so run init here. */ - if (!_initWinsock()) { - return INVALID_SOCKET; - } - - _updateErrno((s = socket(domain, type, protocol)) != INVALID_SOCKET); - return s; -} - -int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp) { - int ret = ioctlsocket(fd, (long)request, argp); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) { - int ret = bind(sockfd, addr, addrlen); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) { - int ret = connect(sockfd, addr, addrlen); - _updateErrno(ret != SOCKET_ERROR); - - /* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as - * EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX - * logic consistent. */ - if (errno == EWOULDBLOCK) { - errno = EINPROGRESS; - } - - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) { - int ret = 0; - if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) { - if (*optlen >= sizeof (struct timeval)) { - struct timeval *tv = optval; - DWORD timeout = 0; - socklen_t dwlen = 0; - ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen); - tv->tv_sec = timeout / 1000; - tv->tv_usec = (timeout * 1000) % 1000000; - } else { - ret = WSAEFAULT; - } - *optlen = sizeof (struct timeval); - } else { - ret = getsockopt(sockfd, level, optname, (char*)optval, optlen); - } - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) { - int ret = 0; - if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) { - const struct timeval *tv = optval; - DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; - ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD)); - } else { - ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen); - } - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_close(SOCKET fd) { - int ret = closesocket(fd); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags) { - int ret = recv(sockfd, (char*)buf, (int)len, flags); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags) { - int ret = send(sockfd, (const char*)buf, (int)len, flags); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} - -int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) { - int ret = WSAPoll(fds, nfds, timeout); - _updateErrno(ret != SOCKET_ERROR); - return ret != SOCKET_ERROR ? ret : -1; -} -#endif /* _WIN32 */ diff --git a/ext/hiredis-1.0.2/sockcompat.h b/ext/hiredis-1.0.2/sockcompat.h deleted file mode 100644 index 85810e84..00000000 --- a/ext/hiredis-1.0.2/sockcompat.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019, Marcus Geelnard - * - * 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 __SOCKCOMPAT_H -#define __SOCKCOMPAT_H - -#ifndef _WIN32 -/* For POSIX systems we use the standard BSD socket API. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#else -/* For Windows we use winsock. */ -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */ -#include -#include -#include -#include - -#ifdef _MSC_VER -typedef long long ssize_t; -#endif - -/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */ -int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); -const char *win32_gai_strerror(int errcode); -void win32_freeaddrinfo(struct addrinfo *res); -SOCKET win32_socket(int domain, int type, int protocol); -int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp); -int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen); -int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen); -int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen); -int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen); -int win32_close(SOCKET fd); -ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags); -ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags); -typedef ULONG nfds_t; -int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout); - -#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION -#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res) -#undef gai_strerror -#define gai_strerror(errcode) win32_gai_strerror(errcode) -#define freeaddrinfo(res) win32_freeaddrinfo(res) -#define socket(domain, type, protocol) win32_socket(domain, type, protocol) -#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp) -#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen) -#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen) -#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen) -#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen) -#define close(fd) win32_close(fd) -#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags) -#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags) -#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout) -#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */ -#endif /* _WIN32 */ - -#endif /* __SOCKCOMPAT_H */ diff --git a/ext/hiredis-1.0.2/ssl.c b/ext/hiredis-1.0.2/ssl.c deleted file mode 100644 index 7df58fbd..00000000 --- a/ext/hiredis-1.0.2/ssl.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * Copyright (c) 2019, Redis Labs - * - * 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 "hiredis.h" -#include "async.h" - -#include -#include -#include -#ifdef _WIN32 -#include -#else -#include -#endif - -#include -#include - -#include "win32.h" -#include "async_private.h" -#include "hiredis_ssl.h" - -void __redisSetError(redisContext *c, int type, const char *str); - -struct redisSSLContext { - /* Associated OpenSSL SSL_CTX as created by redisCreateSSLContext() */ - SSL_CTX *ssl_ctx; - - /* Requested SNI, or NULL */ - char *server_name; -}; - -/* The SSL connection context is attached to SSL/TLS connections as a privdata. */ -typedef struct redisSSL { - /** - * OpenSSL SSL object. - */ - SSL *ssl; - - /** - * SSL_write() requires to be called again with the same arguments it was - * previously called with in the event of an SSL_read/SSL_write situation - */ - size_t lastLen; - - /** Whether the SSL layer requires read (possibly before a write) */ - int wantRead; - - /** - * Whether a write was requested prior to a read. If set, the write() - * should resume whenever a read takes place, if possible - */ - int pendingWrite; -} redisSSL; - -/* Forward declaration */ -redisContextFuncs redisContextSSLFuncs; - -/** - * OpenSSL global initialization and locking handling callbacks. - * Note that this is only required for OpenSSL < 1.1.0. - */ - -#if OPENSSL_VERSION_NUMBER < 0x10100000L -#define HIREDIS_USE_CRYPTO_LOCKS -#endif - -#ifdef HIREDIS_USE_CRYPTO_LOCKS -#ifdef _WIN32 -typedef CRITICAL_SECTION sslLockType; -static void sslLockInit(sslLockType* l) { - InitializeCriticalSection(l); -} -static void sslLockAcquire(sslLockType* l) { - EnterCriticalSection(l); -} -static void sslLockRelease(sslLockType* l) { - LeaveCriticalSection(l); -} -#else -typedef pthread_mutex_t sslLockType; -static void sslLockInit(sslLockType *l) { - pthread_mutex_init(l, NULL); -} -static void sslLockAcquire(sslLockType *l) { - pthread_mutex_lock(l); -} -static void sslLockRelease(sslLockType *l) { - pthread_mutex_unlock(l); -} -#endif - -static sslLockType* ossl_locks; - -static void opensslDoLock(int mode, int lkid, const char *f, int line) { - sslLockType *l = ossl_locks + lkid; - - if (mode & CRYPTO_LOCK) { - sslLockAcquire(l); - } else { - sslLockRelease(l); - } - - (void)f; - (void)line; -} - -static int initOpensslLocks(void) { - unsigned ii, nlocks; - if (CRYPTO_get_locking_callback() != NULL) { - /* Someone already set the callback before us. Don't destroy it! */ - return REDIS_OK; - } - nlocks = CRYPTO_num_locks(); - ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks); - if (ossl_locks == NULL) - return REDIS_ERR; - - for (ii = 0; ii < nlocks; ii++) { - sslLockInit(ossl_locks + ii); - } - CRYPTO_set_locking_callback(opensslDoLock); - return REDIS_OK; -} -#endif /* HIREDIS_USE_CRYPTO_LOCKS */ - -int redisInitOpenSSL(void) -{ - SSL_library_init(); -#ifdef HIREDIS_USE_CRYPTO_LOCKS - initOpensslLocks(); -#endif - - return REDIS_OK; -} - -/** - * redisSSLContext helper context destruction. - */ - -const char *redisSSLContextGetError(redisSSLContextError error) -{ - switch (error) { - case REDIS_SSL_CTX_NONE: - return "No Error"; - case REDIS_SSL_CTX_CREATE_FAILED: - return "Failed to create OpenSSL SSL_CTX"; - case REDIS_SSL_CTX_CERT_KEY_REQUIRED: - return "Client cert and key must both be specified or skipped"; - case REDIS_SSL_CTX_CA_CERT_LOAD_FAILED: - return "Failed to load CA Certificate or CA Path"; - case REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED: - return "Failed to load client certificate"; - case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED: - return "Failed to load private key"; - default: - return "Unknown error code"; - } -} - -void redisFreeSSLContext(redisSSLContext *ctx) -{ - if (!ctx) - return; - - if (ctx->server_name) { - hi_free(ctx->server_name); - ctx->server_name = NULL; - } - - if (ctx->ssl_ctx) { - SSL_CTX_free(ctx->ssl_ctx); - ctx->ssl_ctx = NULL; - } - - hi_free(ctx); -} - - -/** - * redisSSLContext helper context initialization. - */ - -redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *capath, - const char *cert_filename, const char *private_key_filename, - const char *server_name, redisSSLContextError *error) -{ - redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext)); - if (ctx == NULL) - goto error; - - ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); - if (!ctx->ssl_ctx) { - if (error) *error = REDIS_SSL_CTX_CREATE_FAILED; - goto error; - } - - SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); - - if ((cert_filename != NULL && private_key_filename == NULL) || - (private_key_filename != NULL && cert_filename == NULL)) { - if (error) *error = REDIS_SSL_CTX_CERT_KEY_REQUIRED; - goto error; - } - - if (capath || cacert_filename) { - if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) { - if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED; - goto error; - } - } - - if (cert_filename) { - if (!SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, cert_filename)) { - if (error) *error = REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED; - goto error; - } - if (!SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, private_key_filename, SSL_FILETYPE_PEM)) { - if (error) *error = REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED; - goto error; - } - } - - if (server_name) - ctx->server_name = hi_strdup(server_name); - - return ctx; - -error: - redisFreeSSLContext(ctx); - return NULL; -} - -/** - * SSL Connection initialization. - */ - - -static int redisSSLConnect(redisContext *c, SSL *ssl) { - if (c->privctx) { - __redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated"); - return REDIS_ERR; - } - - redisSSL *rssl = hi_calloc(1, sizeof(redisSSL)); - if (rssl == NULL) { - __redisSetError(c, REDIS_ERR_OOM, "Out of memory"); - return REDIS_ERR; - } - - c->funcs = &redisContextSSLFuncs; - rssl->ssl = ssl; - - SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_set_fd(rssl->ssl, c->fd); - SSL_set_connect_state(rssl->ssl); - - ERR_clear_error(); - int rv = SSL_connect(rssl->ssl); - if (rv == 1) { - c->privctx = rssl; - return REDIS_OK; - } - - rv = SSL_get_error(rssl->ssl, rv); - if (((c->flags & REDIS_BLOCK) == 0) && - (rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) { - c->privctx = rssl; - return REDIS_OK; - } - - if (c->err == 0) { - char err[512]; - if (rv == SSL_ERROR_SYSCALL) - snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno)); - else { - unsigned long e = ERR_peek_last_error(); - snprintf(err,sizeof(err)-1,"SSL_connect failed: %s", - ERR_reason_error_string(e)); - } - __redisSetError(c, REDIS_ERR_IO, err); - } - - hi_free(rssl); - return REDIS_ERR; -} - -/** - * A wrapper around redisSSLConnect() for users who manage their own context and - * create their own SSL object. - */ - -int redisInitiateSSL(redisContext *c, SSL *ssl) { - return redisSSLConnect(c, ssl); -} - -/** - * A wrapper around redisSSLConnect() for users who use redisSSLContext and don't - * manage their own SSL objects. - */ - -int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx) -{ - if (!c || !redis_ssl_ctx) - return REDIS_ERR; - - /* We want to verify that redisSSLConnect() won't fail on this, as it will - * not own the SSL object in that case and we'll end up leaking. - */ - if (c->privctx) - return REDIS_ERR; - - SSL *ssl = SSL_new(redis_ssl_ctx->ssl_ctx); - if (!ssl) { - __redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance"); - goto error; - } - - if (redis_ssl_ctx->server_name) { - if (!SSL_set_tlsext_host_name(ssl, redis_ssl_ctx->server_name)) { - __redisSetError(c, REDIS_ERR_OTHER, "Failed to set server_name/SNI"); - goto error; - } - } - - return redisSSLConnect(c, ssl); - -error: - if (ssl) - SSL_free(ssl); - return REDIS_ERR; -} - -static int maybeCheckWant(redisSSL *rssl, int rv) { - /** - * If the error is WANT_READ or WANT_WRITE, the appropriate flags are set - * and true is returned. False is returned otherwise - */ - if (rv == SSL_ERROR_WANT_READ) { - rssl->wantRead = 1; - return 1; - } else if (rv == SSL_ERROR_WANT_WRITE) { - rssl->pendingWrite = 1; - return 1; - } else { - return 0; - } -} - -/** - * Implementation of redisContextFuncs for SSL connections. - */ - -static void redisSSLFree(void *privctx){ - redisSSL *rsc = privctx; - - if (!rsc) return; - if (rsc->ssl) { - SSL_free(rsc->ssl); - rsc->ssl = NULL; - } - hi_free(rsc); -} - -static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) { - redisSSL *rssl = c->privctx; - - int nread = SSL_read(rssl->ssl, buf, bufcap); - if (nread > 0) { - return nread; - } else if (nread == 0) { - __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection"); - return -1; - } else { - int err = SSL_get_error(rssl->ssl, nread); - if (c->flags & REDIS_BLOCK) { - /** - * In blocking mode, we should never end up in a situation where - * we get an error without it being an actual error, except - * in the case of EINTR, which can be spuriously received from - * debuggers or whatever. - */ - if (errno == EINTR) { - return 0; - } else { - const char *msg = NULL; - if (errno == EAGAIN) { - msg = "Resource temporarily unavailable"; - } - __redisSetError(c, REDIS_ERR_IO, msg); - return -1; - } - } - - /** - * We can very well get an EWOULDBLOCK/EAGAIN, however - */ - if (maybeCheckWant(rssl, err)) { - return 0; - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } -} - -static ssize_t redisSSLWrite(redisContext *c) { - redisSSL *rssl = c->privctx; - - size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf); - int rv = SSL_write(rssl->ssl, c->obuf, len); - - if (rv > 0) { - rssl->lastLen = 0; - } else if (rv < 0) { - rssl->lastLen = len; - - int err = SSL_get_error(rssl->ssl, rv); - if ((c->flags & REDIS_BLOCK) == 0 && maybeCheckWant(rssl, err)) { - return 0; - } else { - __redisSetError(c, REDIS_ERR_IO, NULL); - return -1; - } - } - return rv; -} - -static void redisSSLAsyncRead(redisAsyncContext *ac) { - int rv; - redisSSL *rssl = ac->c.privctx; - redisContext *c = &ac->c; - - rssl->wantRead = 0; - - if (rssl->pendingWrite) { - int done; - - /* This is probably just a write event */ - rssl->pendingWrite = 0; - rv = redisBufferWrite(c, &done); - if (rv == REDIS_ERR) { - __redisAsyncDisconnect(ac); - return; - } else if (!done) { - _EL_ADD_WRITE(ac); - } - } - - rv = redisBufferRead(c); - if (rv == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - _EL_ADD_READ(ac); - redisProcessCallbacks(ac); - } -} - -static void redisSSLAsyncWrite(redisAsyncContext *ac) { - int rv, done = 0; - redisSSL *rssl = ac->c.privctx; - redisContext *c = &ac->c; - - rssl->pendingWrite = 0; - rv = redisBufferWrite(c, &done); - if (rv == REDIS_ERR) { - __redisAsyncDisconnect(ac); - return; - } - - if (!done) { - if (rssl->wantRead) { - /* Need to read-before-write */ - rssl->pendingWrite = 1; - _EL_DEL_WRITE(ac); - } else { - /* No extra reads needed, just need to write more */ - _EL_ADD_WRITE(ac); - } - } else { - /* Already done! */ - _EL_DEL_WRITE(ac); - } - - /* Always reschedule a read */ - _EL_ADD_READ(ac); -} - -redisContextFuncs redisContextSSLFuncs = { - .free_privctx = redisSSLFree, - .async_read = redisSSLAsyncRead, - .async_write = redisSSLAsyncWrite, - .read = redisSSLRead, - .write = redisSSLWrite -}; - diff --git a/ext/hiredis-1.0.2/test.c b/ext/hiredis-1.0.2/test.c deleted file mode 100644 index 397f5640..00000000 --- a/ext/hiredis-1.0.2/test.c +++ /dev/null @@ -1,1401 +0,0 @@ -#include "fmacros.h" -#include "sockcompat.h" -#include -#include -#include -#ifndef _WIN32 -#include -#include -#endif -#include -#include -#include -#include - -#include "hiredis.h" -#include "async.h" -#ifdef HIREDIS_TEST_SSL -#include "hiredis_ssl.h" -#endif -#include "net.h" -#include "win32.h" - -enum connection_type { - CONN_TCP, - CONN_UNIX, - CONN_FD, - CONN_SSL -}; - -struct config { - enum connection_type type; - - struct { - const char *host; - int port; - struct timeval timeout; - } tcp; - - struct { - const char *path; - } unix_sock; - - struct { - const char *host; - int port; - const char *ca_cert; - const char *cert; - const char *key; - } ssl; -}; - -struct privdata { - int dtor_counter; -}; - -#ifdef HIREDIS_TEST_SSL -redisSSLContext *_ssl_ctx = NULL; -#endif - -/* The following lines make up our testing "framework" :) */ -static int tests = 0, fails = 0, skips = 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++;} -#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; } - -static long long usec(void) { -#ifndef _MSC_VER - struct timeval tv; - gettimeofday(&tv,NULL); - return (((long long)tv.tv_sec)*1000000)+tv.tv_usec; -#else - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return (((long long)ft.dwHighDateTime << 32) | ft.dwLowDateTime) / 10; -#endif -} - -/* 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 - -/* Helper to extract Redis version information. Aborts on any failure. */ -#define REDIS_VERSION_FIELD "redis_version:" -void get_redis_version(redisContext *c, int *majorptr, int *minorptr) { - redisReply *reply; - char *eptr, *s, *e; - int major, minor; - - reply = redisCommand(c, "INFO"); - if (reply == NULL || c->err || reply->type != REDIS_REPLY_STRING) - goto abort; - if ((s = strstr(reply->str, REDIS_VERSION_FIELD)) == NULL) - goto abort; - - s += strlen(REDIS_VERSION_FIELD); - - /* We need a field terminator and at least 'x.y.z' (5) bytes of data */ - if ((e = strstr(s, "\r\n")) == NULL || (e - s) < 5) - goto abort; - - /* Extract version info */ - major = strtol(s, &eptr, 10); - if (*eptr != '.') goto abort; - minor = strtol(eptr+1, NULL, 10); - - /* Push info the caller wants */ - if (majorptr) *majorptr = major; - if (minorptr) *minorptr = minor; - - freeReplyObject(reply); - return; - -abort: - freeReplyObject(reply); - fprintf(stderr, "Error: Cannot determine Redis version, aborting\n"); - exit(1); -} - -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; -} - -/* Switch protocol */ -static void send_hello(redisContext *c, int version) { - redisReply *reply; - int expected; - - reply = redisCommand(c, "HELLO %d", version); - expected = version == 3 ? REDIS_REPLY_MAP : REDIS_REPLY_ARRAY; - assert(reply != NULL && reply->type == expected); - freeReplyObject(reply); -} - -/* Togggle client tracking */ -static void send_client_tracking(redisContext *c, const char *str) { - redisReply *reply; - - reply = redisCommand(c, "CLIENT TRACKING %s", str); - assert(reply != NULL && reply->type == REDIS_REPLY_STATUS); - freeReplyObject(reply); -} - -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 void do_ssl_handshake(redisContext *c) { -#ifdef HIREDIS_TEST_SSL - redisInitiateSSLWithContext(c, _ssl_ctx); - if (c->err) { - printf("SSL error: %s\n", c->errstr); - redisFree(c); - exit(1); - } -#else - (void) c; -#endif -} - -static redisContext *do_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_SSL) { - c = redisConnect(config.ssl.host, config.ssl.port); - } else if (config.type == CONN_UNIX) { - c = redisConnectUnix(config.unix_sock.path); - } else if (config.type == CONN_FD) { - /* Create a dummy connection just to get an fd to inherit */ - redisContext *dummy_ctx = redisConnectUnix(config.unix_sock.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); - } - - if (config.type == CONN_SSL) { - do_ssl_handshake(c); - } - - return select_database(c); -} - -static void do_reconnect(redisContext *c, struct config config) { - redisReconnect(c); - - if (config.type == CONN_SSL) { - do_ssl_handshake(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)); - hi_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)); - hi_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)); - hi_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)); - hi_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)); - hi_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)); - hi_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)); - hi_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)); \ - hi_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)); \ - hi_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)); - hi_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)); - hi_free(cmd); - - sds sds_cmd; - - sds_cmd = NULL; - test("Format command into sds by passing argc/argv without lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL); - test_cond(strncmp(sds_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)); - sdsfree(sds_cmd); - - sds_cmd = NULL; - test("Format command into sds by passing argc/argv with lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens); - test_cond(strncmp(sds_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)); - sdsfree(sds_cmd); -} - -static void test_append_formatted_commands(struct config config) { - redisContext *c; - redisReply *reply; - char *cmd; - int len; - - c = do_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); - - hi_free(cmd); - freeReplyObject(reply); - - disconnect(c, 0); -} - -static void test_reply_reader(void) { - redisReader *reader; - void *reply, *root; - 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); - - reader = redisReaderCreate(); - test("Can handle arbitrarily nested multi-bulks: "); - for (i = 0; i < 128; i++) { - redisReaderFeed(reader,(char*)"*1\r\n", 4); - } - redisReaderFeed(reader,(char*)"$6\r\nLOLWUT\r\n",12); - ret = redisReaderGetReply(reader,&reply); - root = reply; /* Keep track of the root reply */ - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_ARRAY && - ((redisReply*)reply)->elements == 1); - - test("Can parse arbitrarily nested multi-bulks correctly: "); - while(i--) { - assert(reply != NULL && ((redisReply*)reply)->type == REDIS_REPLY_ARRAY); - reply = ((redisReply*)reply)->element[0]; - } - test_cond(((redisReply*)reply)->type == REDIS_REPLY_STRING && - !memcmp(((redisReply*)reply)->str, "LOLWUT", 6)); - freeReplyObject(root); - redisReaderFree(reader); - - test("Correctly parses LLONG_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":9223372036854775807\r\n",22); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->integer == LLONG_MAX); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when > LLONG_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":9223372036854775808\r\n",22); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bad integer value") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Correctly parses LLONG_MIN: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":-9223372036854775808\r\n",23); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->integer == LLONG_MIN); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when < LLONG_MIN: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, ":-9223372036854775809\r\n",23); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bad integer value") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when array < -1: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "*-2\r\n+asdf\r\n",12); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when bulk < -1: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "$-2\r\nasdf\r\n",11); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bulk string length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Can configure maximum multi-bulk elements: "); - reader = redisReaderCreate(); - reader->maxelements = 1024; - redisReaderFeed(reader, "*1025\r\n", 7); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr, "Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Multi-bulk never overflows regardless of maxelements: "); - size_t bad_mbulk_len = (SIZE_MAX / sizeof(void *)) + 3; - char bad_mbulk_reply[100]; - snprintf(bad_mbulk_reply, sizeof(bad_mbulk_reply), "*%llu\r\n+asdf\r\n", - (unsigned long long) bad_mbulk_len); - - reader = redisReaderCreate(); - reader->maxelements = 0; /* Don't rely on default limit */ - redisReaderFeed(reader, bad_mbulk_reply, strlen(bad_mbulk_reply)); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && strcasecmp(reader->errstr, "Out of memory") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - -#if LLONG_MAX > SIZE_MAX - test("Set error when array > SIZE_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); - - test("Set error when bulk > SIZE_MAX: "); - reader = redisReaderCreate(); - redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Bulk string length out of range") == 0); - freeReplyObject(reply); - redisReaderFree(reader); -#endif - - 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); - - /* RESP3 verbatim strings (GitHub issue #802) */ - test("Can parse RESP3 verbatim strings: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"=10\r\ntxt:LOLWUT\r\n",17); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_VERB && - !memcmp(((redisReply*)reply)->str,"LOLWUT", 6)); - freeReplyObject(reply); - redisReaderFree(reader); - - /* RESP3 push messages (Github issue #815) */ - test("Can parse RESP3 push messages: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)">2\r\n$6\r\nLOLWUT\r\n:42\r\n",21); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_PUSH && - ((redisReply*)reply)->elements == 2 && - ((redisReply*)reply)->element[0]->type == REDIS_REPLY_STRING && - !memcmp(((redisReply*)reply)->element[0]->str,"LOLWUT",6) && - ((redisReply*)reply)->element[1]->type == REDIS_REPLY_INTEGER && - ((redisReply*)reply)->element[1]->integer == 42); - freeReplyObject(reply); - redisReaderFree(reader); -} - -static void test_free_null(void) { - void *redisCtx = NULL; - void *reply = NULL; - - test("Don't fail when redisFree is passed a NULL value: "); - redisFree(redisCtx); - test_cond(redisCtx == NULL); - - test("Don't fail when freeReplyObject is passed a NULL value: "); - freeReplyObject(reply); - test_cond(reply == NULL); -} - -static void *hi_malloc_fail(size_t size) { - (void)size; - return NULL; -} - -static void *hi_calloc_fail(size_t nmemb, size_t size) { - (void)nmemb; - (void)size; - return NULL; -} - -static void *hi_realloc_fail(void *ptr, size_t size) { - (void)ptr; - (void)size; - return NULL; -} - -static void test_allocator_injection(void) { - hiredisAllocFuncs ha = { - .mallocFn = hi_malloc_fail, - .callocFn = hi_calloc_fail, - .reallocFn = hi_realloc_fail, - .strdupFn = strdup, - .freeFn = free, - }; - - // Override hiredis allocators - hiredisSetAllocators(&ha); - - test("redisContext uses injected allocators: "); - redisContext *c = redisConnect("localhost", 6379); - test_cond(c == NULL); - - test("redisReader uses injected allocators: "); - redisReader *reader = redisReaderCreate(); - test_cond(reader == NULL); - - // Return allocators to default - hiredisResetAllocators(); -} - -#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com" -static void test_blocking_connection_errors(void) { - redisContext *c; - struct addrinfo hints = {.ai_family = AF_INET}; - struct addrinfo *ai_tmp = NULL; - - int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp); - if (rv != 0) { - // Address does *not* exist - test("Returns error when host cannot be resolved: "); - // First see if this domain name *actually* resolves to NXDOMAIN - c = redisConnect(HIREDIS_BAD_DOMAIN, 6379); - test_cond( - c->err == REDIS_ERR_OTHER && - (strcmp(c->errstr, "Name or service not known") == 0 || - strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 || - strcmp(c->errstr, "Name does not resolve") == 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, "hostname nor servname provided, or not known") == 0 || - strcmp(c->errstr, "no address associated with name") == 0 || - strcmp(c->errstr, "No such host is known. ") == 0)); - redisFree(c); - } else { - printf("Skipping NXDOMAIN test. Found evil ISP!\n"); - freeaddrinfo(ai_tmp); - } - -#ifndef _WIN32 - 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_sock 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); -#endif -} - -/* Dummy push handler */ -void push_handler(void *privdata, void *reply) { - int *counter = privdata; - freeReplyObject(reply); - *counter += 1; -} - -/* Dummy function just to test setting a callback with redisOptions */ -void push_handler_async(redisAsyncContext *ac, void *reply) { - (void)ac; - (void)reply; -} - -static void test_resp3_push_handler(redisContext *c) { - redisPushFn *old = NULL; - redisReply *reply; - void *privdata; - int n = 0; - - /* Switch to RESP3 and turn on client tracking */ - send_hello(c, 3); - send_client_tracking(c, "ON"); - privdata = c->privdata; - c->privdata = &n; - - reply = redisCommand(c, "GET key:0"); - assert(reply != NULL); - freeReplyObject(reply); - - test("RESP3 PUSH messages are handled out of band by default: "); - reply = redisCommand(c, "SET key:0 val:0"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS); - freeReplyObject(reply); - - assert((reply = redisCommand(c, "GET key:0")) != NULL); - freeReplyObject(reply); - - old = redisSetPushCallback(c, push_handler); - test("We can set a custom RESP3 PUSH handler: "); - reply = redisCommand(c, "SET key:0 val:0"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && n == 1); - freeReplyObject(reply); - - /* Unset the push callback and generate an invalidate message making - * sure it is not handled out of band. */ - test("With no handler, PUSH replies come in-band: "); - redisSetPushCallback(c, NULL); - assert((reply = redisCommand(c, "GET key:0")) != NULL); - freeReplyObject(reply); - assert((reply = redisCommand(c, "SET key:0 invalid")) != NULL); - test_cond(reply->type == REDIS_REPLY_PUSH); - freeReplyObject(reply); - - test("With no PUSH handler, no replies are lost: "); - assert(redisGetReply(c, (void**)&reply) == REDIS_OK); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS); - freeReplyObject(reply); - - /* Return to the originally set PUSH handler */ - assert(old != NULL); - redisSetPushCallback(c, old); - - /* Switch back to RESP2 and disable tracking */ - c->privdata = privdata; - send_client_tracking(c, "OFF"); - send_hello(c, 2); -} - -redisOptions get_redis_tcp_options(struct config config) { - redisOptions options = {0}; - REDIS_OPTIONS_SET_TCP(&options, config.tcp.host, config.tcp.port); - return options; -} - -static void test_resp3_push_options(struct config config) { - redisAsyncContext *ac; - redisContext *c; - redisOptions options; - - test("We set a default RESP3 handler for redisContext: "); - options = get_redis_tcp_options(config); - assert((c = redisConnectWithOptions(&options)) != NULL); - test_cond(c->push_cb != NULL); - redisFree(c); - - test("We don't set a default RESP3 push handler for redisAsyncContext: "); - options = get_redis_tcp_options(config); - assert((ac = redisAsyncConnectWithOptions(&options)) != NULL); - test_cond(ac->c.push_cb == NULL); - redisAsyncFree(ac); - - test("Our REDIS_OPT_NO_PUSH_AUTOFREE flag works: "); - options = get_redis_tcp_options(config); - options.options |= REDIS_OPT_NO_PUSH_AUTOFREE; - assert((c = redisConnectWithOptions(&options)) != NULL); - test_cond(c->push_cb == NULL); - redisFree(c); - - test("We can use redisOptions to set a custom PUSH handler for redisContext: "); - options = get_redis_tcp_options(config); - options.push_cb = push_handler; - assert((c = redisConnectWithOptions(&options)) != NULL); - test_cond(c->push_cb == push_handler); - redisFree(c); - - test("We can use redisOptions to set a custom PUSH handler for redisAsyncContext: "); - options = get_redis_tcp_options(config); - options.async_push_cb = push_handler_async; - assert((ac = redisAsyncConnectWithOptions(&options)) != NULL); - test_cond(ac->push_cb == push_handler_async); - redisAsyncFree(ac); -} - -void free_privdata(void *privdata) { - struct privdata *data = privdata; - data->dtor_counter++; -} - -static void test_privdata_hooks(struct config config) { - struct privdata data = {0}; - redisOptions options; - redisContext *c; - - test("We can use redisOptions to set privdata: "); - options = get_redis_tcp_options(config); - REDIS_OPTIONS_SET_PRIVDATA(&options, &data, free_privdata); - assert((c = redisConnectWithOptions(&options)) != NULL); - test_cond(c->privdata == &data); - - test("Our privdata destructor fires when we free the context: "); - redisFree(c); - test_cond(data.dtor_counter == 1); -} - -static void test_blocking_connection(struct config config) { - redisContext *c; - redisReply *reply; - int major; - - c = do_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); - - /* Make sure passing NULL to redisGetReply is safe */ - test("Can pass NULL to redisGetReply: "); - assert(redisAppendCommand(c, "PING") == REDIS_OK); - test_cond(redisGetReply(c, NULL) == REDIS_OK); - - get_redis_version(c, &major, NULL); - if (major >= 6) test_resp3_push_handler(c); - test_resp3_push_options(config); - - test_privdata_hooks(config); - - disconnect(c, 0); -} - -/* Send DEBUG SLEEP 0 to detect if we have this command */ -static int detect_debug_sleep(redisContext *c) { - int detected; - redisReply *reply = redisCommand(c, "DEBUG SLEEP 0\r\n"); - - if (reply == NULL || c->err) { - const char *cause = c->err ? c->errstr : "(none)"; - fprintf(stderr, "Error testing for DEBUG SLEEP (Redis error: %s), exiting\n", cause); - exit(-1); - } - - detected = reply->type == REDIS_REPLY_STATUS; - freeReplyObject(reply); - - return detected; -} - -static void test_blocking_connection_timeouts(struct config config) { - redisContext *c; - redisReply *reply; - ssize_t s; - const char *sleep_cmd = "DEBUG SLEEP 3\r\n"; - struct timeval tv; - - c = do_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 = do_connect(config); - test("Does not return a reply when the command times out: "); - if (detect_debug_sleep(c)) { - redisAppendFormattedCommand(c, sleep_cmd, strlen(sleep_cmd)); - s = c->funcs->write(c); - tv.tv_sec = 0; - tv.tv_usec = 10000; - redisSetTimeout(c, tv); - reply = redisCommand(c, "GET foo"); -#ifndef _WIN32 - test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && - strcmp(c->errstr, "Resource temporarily unavailable") == 0); -#else - test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_TIMEOUT && - strcmp(c->errstr, "recv timeout") == 0); -#endif - freeReplyObject(reply); - } else { - test_skipped(); - } - - test("Reconnect properly reconnects after a timeout: "); - do_reconnect(c, config); - 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_sock.path = "foo"; - do_reconnect(c, config); - 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 = do_connect(config); - get_redis_version(c, &major, &minor); - - 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); - } - -#ifndef _WIN32 - /* 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); -#endif - redisFree(c); - - c = do_connect(config); - test("Returns I/O error on socket timeout: "); - struct timeval tv = { 0, 1000 }; - assert(redisSetTimeout(c,tv) == REDIS_OK); - int respcode = redisGetReply(c,&_reply); -#ifndef _WIN32 - test_cond(respcode == REDIS_ERR && c->err == REDIS_ERR_IO && errno == EAGAIN); -#else - test_cond(respcode == REDIS_ERR && c->err == REDIS_ERR_TIMEOUT); -#endif - 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 && strcmp(c->errstr, "Invalid timeout specified") == 0); - 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 && strcmp(c->errstr, "Invalid timeout specified") == 0); - redisFree(c); -} - -/* Wrap malloc to abort on failure so OOM checks don't make the test logic - * harder to follow. */ -void *hi_malloc_safe(size_t size) { - void *ptr = hi_malloc(size); - if (ptr == NULL) { - fprintf(stderr, "Error: Out of memory\n"); - exit(-1); - } - - return ptr; -} - -static void test_throughput(struct config config) { - redisContext *c = do_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 = hi_malloc_safe(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]); - hi_free(replies); - printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = hi_malloc_safe(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]); - hi_free(replies); - printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = hi_malloc_safe(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - hi_free(replies); - printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0); - - num = 10000; - replies = hi_malloc_safe(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]); - hi_free(replies); - printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = hi_malloc_safe(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]); - hi_free(replies); - printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = hi_malloc_safe(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"INCRBY incrkey %d", 1000000); - 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_INTEGER); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - hi_free(replies); - printf("\t(%dx INCRBY (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_sock = { - .path = "/tmp/redis.sock" - } - }; - int throughput = 1; - int test_inherit_fd = 1; - int skips_as_fails = 0; - int test_unix_socket; - - /* 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_sock.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 if (argc >= 1 && !strcmp(argv[0],"--skips-as-fails")) { - skips_as_fails = 1; -#ifdef HIREDIS_TEST_SSL - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-port")) { - argv++; argc--; - cfg.ssl.port = atoi(argv[0]); - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-host")) { - argv++; argc--; - cfg.ssl.host = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-ca-cert")) { - argv++; argc--; - cfg.ssl.ca_cert = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-cert")) { - argv++; argc--; - cfg.ssl.cert = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"--ssl-key")) { - argv++; argc--; - cfg.ssl.key = argv[0]; -#endif - } else { - fprintf(stderr, "Invalid argument: %s\n", argv[0]); - exit(1); - } - argv++; argc--; - } - -#ifndef _WIN32 - /* Ignore broken pipe signal (for I/O error tests). */ - signal(SIGPIPE, SIG_IGN); - - test_unix_socket = access(cfg.unix_sock.path, F_OK) == 0; - -#else - /* Unix sockets don't exist in Windows */ - test_unix_socket = 0; -#endif - - test_allocator_injection(); - - 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): ", cfg.unix_sock.path); - if (test_unix_socket) { - printf("\n"); - cfg.type = CONN_UNIX; - test_blocking_connection(cfg); - test_blocking_connection_timeouts(cfg); - test_blocking_io_errors(cfg); - if (throughput) test_throughput(cfg); - } else { - test_skipped(); - } - -#ifdef HIREDIS_TEST_SSL - if (cfg.ssl.port && cfg.ssl.host) { - - redisInitOpenSSL(); - _ssl_ctx = redisCreateSSLContext(cfg.ssl.ca_cert, NULL, cfg.ssl.cert, cfg.ssl.key, NULL, NULL); - assert(_ssl_ctx != NULL); - - printf("\nTesting against SSL connection (%s:%d):\n", cfg.ssl.host, cfg.ssl.port); - cfg.type = CONN_SSL; - - 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); - - redisFreeSSLContext(_ssl_ctx); - _ssl_ctx = NULL; - } -#endif - - if (test_inherit_fd) { - printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path); - if (test_unix_socket) { - printf("\n"); - cfg.type = CONN_FD; - test_blocking_connection(cfg); - } else { - test_skipped(); - } - } - - if (fails || (skips_as_fails && skips)) { - printf("*** %d TESTS FAILED ***\n", fails); - if (skips) { - printf("*** %d TESTS SKIPPED ***\n", skips); - } - return 1; - } - - printf("ALL TESTS PASSED (%d skipped)\n", skips); - return 0; -} diff --git a/ext/hiredis-1.0.2/test.sh b/ext/hiredis-1.0.2/test.sh deleted file mode 100755 index c72bcb0d..00000000 --- a/ext/hiredis-1.0.2/test.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh -ue - -REDIS_SERVER=${REDIS_SERVER:-redis-server} -REDIS_PORT=${REDIS_PORT:-56379} -REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443} -TEST_SSL=${TEST_SSL:-0} -SKIPS_AS_FAILS=${SKIPS_AS_FAILS-:0} -SSL_TEST_ARGS= -SKIPS_ARG= - -tmpdir=$(mktemp -d) -PID_FILE=${tmpdir}/hiredis-test-redis.pid -SOCK_FILE=${tmpdir}/hiredis-test-redis.sock - -if [ "$TEST_SSL" = "1" ]; then - SSL_CA_CERT=${tmpdir}/ca.crt - SSL_CA_KEY=${tmpdir}/ca.key - SSL_CERT=${tmpdir}/redis.crt - SSL_KEY=${tmpdir}/redis.key - - openssl genrsa -out ${tmpdir}/ca.key 4096 - openssl req \ - -x509 -new -nodes -sha256 \ - -key ${SSL_CA_KEY} \ - -days 3650 \ - -subj '/CN=Hiredis Test CA' \ - -out ${SSL_CA_CERT} - openssl genrsa -out ${SSL_KEY} 2048 - openssl req \ - -new -sha256 \ - -key ${SSL_KEY} \ - -subj '/CN=Hiredis Test Cert' | \ - openssl x509 \ - -req -sha256 \ - -CA ${SSL_CA_CERT} \ - -CAkey ${SSL_CA_KEY} \ - -CAserial ${tmpdir}/ca.txt \ - -CAcreateserial \ - -days 365 \ - -out ${SSL_CERT} - - SSL_TEST_ARGS="--ssl-host 127.0.0.1 --ssl-port ${REDIS_SSL_PORT} --ssl-ca-cert ${SSL_CA_CERT} --ssl-cert ${SSL_CERT} --ssl-key ${SSL_KEY}" -fi - -cleanup() { - set +e - kill $(cat ${PID_FILE}) - rm -rf ${tmpdir} -} -trap cleanup INT TERM EXIT - -cat > ${tmpdir}/redis.conf <> ${tmpdir}/redis.conf < /* for struct timeval */ - -#ifndef inline -#define inline __inline -#endif - -#ifndef strcasecmp -#define strcasecmp stricmp -#endif - -#ifndef strncasecmp -#define strncasecmp strnicmp -#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 /* _MSC_VER */ - -#ifdef _WIN32 -#define strerror_r(errno,buf,len) strerror_s(buf,len,errno) -#endif /* _WIN32 */ - -#endif /* _WIN32_HELPER_INCLUDE */ diff --git a/ext/http-parser/AUTHORS b/ext/http-parser/AUTHORS deleted file mode 100644 index 5323b685..00000000 --- a/ext/http-parser/AUTHORS +++ /dev/null @@ -1,68 +0,0 @@ -# Authors ordered by first contribution. -Ryan Dahl -Jeremy Hinegardner -Sergey Shepelev -Joe Damato -tomika -Phoenix Sol -Cliff Frey -Ewen Cheslack-Postava -Santiago Gala -Tim Becker -Jeff Terrace -Ben Noordhuis -Nathan Rajlich -Mark Nottingham -Aman Gupta -Tim Becker -Sean Cunningham -Peter Griess -Salman Haq -Cliff Frey -Jon Kolb -Fouad Mardini -Paul Querna -Felix Geisendörfer -koichik -Andre Caron -Ivo Raisr -James McLaughlin -David Gwynne -Thomas LE ROUX -Randy Rizun -Andre Louis Caron -Simon Zimmermann -Erik Dubbelboer -Martell Malone -Bertrand Paquet -BogDan Vatra -Peter Faiman -Corey Richardson -Tóth Tamás -Cam Swords -Chris Dickinson -Uli Köhler -Charlie Somerville -Patrik Stutz -Fedor Indutny -runner -Alexis Campailla -David Wragg -Vinnie Falco -Alex Butum -Rex Feng -Alex Kocharin -Mark Koopman -Helge Heß -Alexis La Goutte -George Miroshnykov -Maciej Małecki -Marc O'Morain -Jeff Pinner -Timothy J Fontaine -Akagi201 -Romain Giraud -Jay Satiro -Arne Steen -Kjell Schubert -Olivier Mengué diff --git a/ext/http-parser/LICENSE-MIT b/ext/http-parser/LICENSE-MIT deleted file mode 100644 index 58010b38..00000000 --- a/ext/http-parser/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. 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. diff --git a/ext/http-parser/README.md b/ext/http-parser/README.md deleted file mode 100644 index 439b3099..00000000 --- a/ext/http-parser/README.md +++ /dev/null @@ -1,246 +0,0 @@ -HTTP Parser -=========== - -[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser) - -This is a parser for HTTP messages written in C. It parses both requests and -responses. The parser is designed to be used in performance HTTP -applications. It does not make any syscalls nor allocations, it does not -buffer data, it can be interrupted at anytime. Depending on your -architecture, it only requires about 40 bytes of data per message -stream (in a web server that is per connection). - -Features: - - * No dependencies - * Handles persistent streams (keep-alive). - * Decodes chunked encoding. - * Upgrade support - * Defends against buffer overflow attacks. - -The parser extracts the following information from HTTP messages: - - * Header fields and values - * Content-Length - * Request method - * Response status code - * Transfer-Encoding - * HTTP version - * Request URL - * Message body - - -Usage ------ - -One `http_parser` object is used per TCP connection. Initialize the struct -using `http_parser_init()` and set the callbacks. That might look something -like this for a request parser: -```c -http_parser_settings settings; -settings.on_url = my_url_callback; -settings.on_header_field = my_header_field_callback; -/* ... */ - -http_parser *parser = malloc(sizeof(http_parser)); -http_parser_init(parser, HTTP_REQUEST); -parser->data = my_socket; -``` - -When data is received on the socket execute the parser and check for errors. - -```c -size_t len = 80*1024, nparsed; -char buf[len]; -ssize_t recved; - -recved = recv(fd, buf, len, 0); - -if (recved < 0) { - /* Handle error. */ -} - -/* Start up / continue the parser. - * Note we pass recved==0 to signal that EOF has been received. - */ -nparsed = http_parser_execute(parser, &settings, buf, recved); - -if (parser->upgrade) { - /* handle new protocol */ -} else if (nparsed != recved) { - /* Handle error. Usually just close the connection. */ -} -``` - -HTTP needs to know where the end of the stream is. For example, sometimes -servers send responses without Content-Length and expect the client to -consume input (for the body) until EOF. To tell http_parser about EOF, give -`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors -can still be encountered during an EOF, so one must still be prepared -to receive them. - -Scalar valued message information such as `status_code`, `method`, and the -HTTP version are stored in the parser structure. This data is only -temporally stored in `http_parser` and gets reset on each new message. If -this information is needed later, copy it out of the structure during the -`headers_complete` callback. - -The parser decodes the transfer-encoding for both requests and responses -transparently. That is, a chunked encoding is decoded before being sent to -the on_body callback. - - -The Special Problem of Upgrade ------------------------------- - -HTTP supports upgrading the connection to a different protocol. An -increasingly common example of this is the WebSocket protocol which sends -a request like - - GET /demo HTTP/1.1 - Upgrade: WebSocket - Connection: Upgrade - Host: example.com - Origin: http://example.com - WebSocket-Protocol: sample - -followed by non-HTTP data. - -(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the -WebSocket protocol.) - -To support this, the parser will treat this as a normal HTTP message without a -body, issuing both on_headers_complete and on_message_complete callbacks. However -http_parser_execute() will stop parsing at the end of the headers and return. - -The user is expected to check if `parser->upgrade` has been set to 1 after -`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied -offset by the return value of `http_parser_execute()`. - - -Callbacks ---------- - -During the `http_parser_execute()` call, the callbacks set in -`http_parser_settings` will be executed. The parser maintains state and -never looks behind, so buffering the data is not necessary. If you need to -save certain data for later usage, you can do that from the callbacks. - -There are two types of callbacks: - -* notification `typedef int (*http_cb) (http_parser*);` - Callbacks: on_message_begin, on_headers_complete, on_message_complete. -* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);` - Callbacks: (requests only) on_url, - (common) on_header_field, on_header_value, on_body; - -Callbacks must return 0 on success. Returning a non-zero value indicates -error to the parser, making it exit immediately. - -For cases where it is necessary to pass local information to/from a callback, -the `http_parser` object's `data` field can be used. -An example of such a case is when using threads to handle a socket connection, -parse a request, and then give a response over that socket. By instantiation -of a thread-local struct containing relevant data (e.g. accepted socket, -allocated memory for callbacks to write into, etc), a parser's callbacks are -able to communicate data between the scope of the thread and the scope of the -callback in a threadsafe manner. This allows http-parser to be used in -multi-threaded contexts. - -Example: -```c - typedef struct { - socket_t sock; - void* buffer; - int buf_len; - } custom_data_t; - - -int my_url_callback(http_parser* parser, const char *at, size_t length) { - /* access to thread local custom_data_t struct. - Use this access save parsed data for later use into thread local - buffer, or communicate over socket - */ - parser->data; - ... - return 0; -} - -... - -void http_parser_thread(socket_t sock) { - int nparsed = 0; - /* allocate memory for user data */ - custom_data_t *my_data = malloc(sizeof(custom_data_t)); - - /* some information for use by callbacks. - * achieves thread -> callback information flow */ - my_data->sock = sock; - - /* instantiate a thread-local parser */ - http_parser *parser = malloc(sizeof(http_parser)); - http_parser_init(parser, HTTP_REQUEST); /* initialise parser */ - /* this custom data reference is accessible through the reference to the - parser supplied to callback functions */ - parser->data = my_data; - - http_parser_settings settings; /* set up callbacks */ - settings.on_url = my_url_callback; - - /* execute parser */ - nparsed = http_parser_execute(parser, &settings, buf, recved); - - ... - /* parsed information copied from callback. - can now perform action on data copied into thread-local memory from callbacks. - achieves callback -> thread information flow */ - my_data->buffer; - ... -} - -``` - -In case you parse HTTP message in chunks (i.e. `read()` request line -from socket, parse, read half headers, parse, etc) your data callbacks -may be called more than once. Http-parser guarantees that data pointer is only -valid for the lifetime of callback. You can also `read()` into a heap allocated -buffer to avoid copying memory around if this fits your application. - -Reading headers may be a tricky task if you read/parse headers partially. -Basically, you need to remember whether last header callback was field or value -and apply the following logic: - - (on_header_field and on_header_value shortened to on_h_*) - ------------------------ ------------ -------------------------------------------- - | State (prev. callback) | Callback | Description/action | - ------------------------ ------------ -------------------------------------------- - | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | - | | | into it | - ------------------------ ------------ -------------------------------------------- - | value | on_h_field | New header started. | - | | | Copy current name,value buffers to headers | - | | | list and allocate new buffer for new name | - ------------------------ ------------ -------------------------------------------- - | field | on_h_field | Previous name continues. Reallocate name | - | | | buffer and append callback data to it | - ------------------------ ------------ -------------------------------------------- - | field | on_h_value | Value for current header started. Allocate | - | | | new buffer and copy callback data to it | - ------------------------ ------------ -------------------------------------------- - | value | on_h_value | Value continues. Reallocate value buffer | - | | | and append callback data to it | - ------------------------ ------------ -------------------------------------------- - - -Parsing URLs ------------- - -A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`. -Users of this library may wish to use it to parse URLs constructed from -consecutive `on_url` callbacks. - -See examples of reading in headers: - -* [partial example](http://gist.github.com/155877) in C -* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C -* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript diff --git a/ext/http-parser/http_parser.c b/ext/http-parser/http_parser.c deleted file mode 100644 index 895bf0c7..00000000 --- a/ext/http-parser/http_parser.c +++ /dev/null @@ -1,2470 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. 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. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - -#define CURRENT_STATE() p_state -#define UPDATE_STATE(V) p_state = (enum state) (V); -#define RETURN(V) \ -do { \ - parser->state = CURRENT_STATE(); \ - return (V); \ -} while (0); -#define REEXECUTE() \ - goto reexecute; \ - - -#ifdef __GNUC__ -# define LIKELY(X) __builtin_expect(!!(X), 1) -# define UNLIKELY(X) __builtin_expect(!!(X), 0) -#else -# define LIKELY(X) (X) -# define UNLIKELY(X) (X) -#endif - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (LIKELY(settings->on_##FOR)) { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (LIKELY(settings->on_##FOR)) { \ - parser->state = CURRENT_STATE(); \ - if (UNLIKELY(0 != \ - settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - UPDATE_STATE(parser->state); \ - \ - /* We either errored above or got paused; get out */ \ - if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - -/* Don't allow the total size of the HTTP headers (including the status - * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect - * embedders against denial-of-service attacks where the attacker feeds - * us a never-ending header that the embedder keeps buffering. - * - * This check is arguably the responsibility of embedders but we're doing - * it on the embedder's behalf because most won't bother and this way we - * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger - * than any reasonable request or response so this should never affect - * day-to-day operation. - */ -#define COUNT_HEADER_SIZE(V) \ -do { \ - parser->nread += (V); \ - if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ - SET_ERRNO(HPE_HEADER_OVERFLOW); \ - goto error; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status_start - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_discard_ws - , s_header_value_discard_ws_almost_done - , s_header_value_discard_lws - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_token_start - , h_matching_connection_keep_alive - , h_matching_connection_close - , h_matching_connection_upgrade - , h_matching_connection_token - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - , h_connection_upgrade - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_v6_zone_start - , s_http_host_v6_zone - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#define STRICT_TOKEN(c) (tokens[(unsigned char)c]) - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - -/** - * Verify that a char is a valid visible (printable) US-ASCII - * character or %x80-FF - **/ -#define IS_HEADER_CHAR(ch) \ - (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127)) - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHA(ch)) { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - const char *status_mark = 0; - enum state p_state = (enum state) parser->state; - const unsigned int lenient = parser->lenient_http_headers; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (CURRENT_STATE()) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (CURRENT_STATE() == s_header_field) - header_field_mark = data; - if (CURRENT_STATE() == s_header_value) - header_value_mark = data; - switch (CURRENT_STATE()) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - case s_res_status: - status_mark = data; - break; - default: - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(CURRENT_STATE())) - COUNT_HEADER_SIZE(1); - -reexecute: - switch (CURRENT_STATE()) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (LIKELY(ch == CR || ch == LF)) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - UPDATE_STATE(s_res_or_resp_H); - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - UPDATE_STATE(s_start_req); - REEXECUTE(); - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - UPDATE_STATE(s_res_HT); - } else { - if (UNLIKELY(ch != 'E')) { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - UPDATE_STATE(s_req_method); - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - UPDATE_STATE(s_res_H); - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HT); - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_res_HTT); - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_res_HTTP); - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_res_first_http_major); - break; - - case s_res_first_http_major: - if (UNLIKELY(ch < '0' || ch > '9')) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_res_http_major); - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - UPDATE_STATE(s_res_first_http_minor); - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (UNLIKELY(parser->http_major > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_res_http_minor); - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - UPDATE_STATE(s_res_first_status_code); - break; - } - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (UNLIKELY(parser->http_minor > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - UPDATE_STATE(s_res_status_code); - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - UPDATE_STATE(s_res_status_start); - break; - case CR: - UPDATE_STATE(s_res_line_almost_done); - break; - case LF: - UPDATE_STATE(s_header_field_start); - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (UNLIKELY(parser->status_code > 999)) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status_start: - { - if (ch == CR) { - UPDATE_STATE(s_res_line_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - break; - } - - MARK(status); - UPDATE_STATE(s_res_status); - parser->index = 0; - break; - } - - case s_res_status: - if (ch == CR) { - UPDATE_STATE(s_res_line_almost_done); - CALLBACK_DATA(status); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA(status); - break; - } - - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_field_start); - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (UNLIKELY(!IS_ALPHA(ch))) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'A': parser->method = HTTP_ACL; break; - case 'B': parser->method = HTTP_BIND; break; - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - UPDATE_STATE(s_req_method); - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (UNLIKELY(ch == '\0')) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - UPDATE_STATE(s_req_spaces_before_url); - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (IS_ALPHA(ch)) { - - switch (parser->method << 16 | parser->index << 8 | ch) { -#define XX(meth, pos, ch, new_meth) \ - case (HTTP_##meth << 16 | pos << 8 | ch): \ - parser->method = HTTP_##new_meth; break; - - XX(POST, 1, 'U', PUT) - XX(POST, 1, 'A', PATCH) - XX(CONNECT, 1, 'H', CHECKOUT) - XX(CONNECT, 2, 'P', COPY) - XX(MKCOL, 1, 'O', MOVE) - XX(MKCOL, 1, 'E', MERGE) - XX(MKCOL, 2, 'A', MKACTIVITY) - XX(MKCOL, 3, 'A', MKCALENDAR) - XX(SUBSCRIBE, 1, 'E', SEARCH) - XX(REPORT, 2, 'B', REBIND) - XX(POST, 1, 'R', PROPFIND) - XX(PROPFIND, 4, 'P', PROPPATCH) - XX(PUT, 2, 'R', PURGE) - XX(LOCK, 1, 'I', LINK) - XX(UNLOCK, 2, 'S', UNSUBSCRIBE) - XX(UNLOCK, 2, 'B', UNBIND) - XX(UNLOCK, 3, 'I', UNLINK) -#undef XX - - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (ch == '-' && - parser->index == 1 && - parser->method == HTTP_MKCOL) { - parser->method = HTTP_MSEARCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - UPDATE_STATE(s_req_server_start); - } - - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - UPDATE_STATE(s_req_http_start); - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - UPDATE_STATE((ch == CR) ? - s_req_line_almost_done : - s_header_field_start); - CALLBACK_DATA(url); - break; - default: - UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); - if (UNLIKELY(CURRENT_STATE() == s_dead)) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - UPDATE_STATE(s_req_http_H); - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HT); - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - UPDATE_STATE(s_req_http_HTT); - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - UPDATE_STATE(s_req_http_HTTP); - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - UPDATE_STATE(s_req_first_http_major); - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (UNLIKELY(ch < '1' || ch > '9')) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - UPDATE_STATE(s_req_http_major); - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - UPDATE_STATE(s_req_first_http_minor); - break; - } - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (UNLIKELY(parser->http_major > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - UPDATE_STATE(s_req_http_minor); - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - UPDATE_STATE(s_req_line_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_field_start); - break; - } - - /* XXX allow spaces after digit? */ - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (UNLIKELY(parser->http_minor > 999)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (UNLIKELY(ch != LF)) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_field_start); - break; - } - - case s_header_field_start: - { - if (ch == CR) { - UPDATE_STATE(s_headers_almost_done); - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - UPDATE_STATE(s_headers_almost_done); - REEXECUTE(); - } - - c = TOKEN(ch); - - if (UNLIKELY(!c)) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - UPDATE_STATE(s_header_field); - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - const char* start = p; - for (; p != data + len; p++) { - ch = *p; - c = TOKEN(ch); - - if (!c) - break; - - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - } - - COUNT_HEADER_SIZE(p - start); - - if (p == data + len) { - --p; - break; - } - - if (ch == ':') { - UPDATE_STATE(s_header_value_discard_ws); - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_discard_ws: - if (ch == ' ' || ch == '\t') break; - - if (ch == CR) { - UPDATE_STATE(s_header_value_discard_ws_almost_done); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - /* FALLTHROUGH */ - - case s_header_value_start: - { - MARK(header_value); - - UPDATE_STATE(s_header_value); - parser->index = 0; - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - if (parser->flags & F_CONTENTLENGTH) { - SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); - goto error; - } - - parser->flags |= F_CONTENTLENGTH; - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else if (c == 'u') { - parser->header_state = h_matching_connection_upgrade; - } else { - parser->header_state = h_matching_connection_token; - } - break; - - /* Multi-value `Connection` header */ - case h_matching_connection_token_start: - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - const char* start = p; - enum header_states h_state = (enum header_states) parser->header_state; - for (; p != data + len; p++) { - ch = *p; - if (ch == CR) { - UPDATE_STATE(s_header_almost_done); - parser->header_state = h_state; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - UPDATE_STATE(s_header_almost_done); - COUNT_HEADER_SIZE(p - start); - parser->header_state = h_state; - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - - if (!lenient && !IS_HEADER_CHAR(ch)) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - c = LOWER(ch); - - switch (h_state) { - case h_general: - { - const char* p_cr; - const char* p_lf; - size_t limit = data + len - p; - - limit = MIN(limit, HTTP_MAX_HEADER_SIZE); - - p_cr = (const char*) memchr(p, CR, limit); - p_lf = (const char*) memchr(p, LF, limit); - if (p_cr != NULL) { - if (p_lf != NULL && p_cr >= p_lf) - p = p_lf; - else - p = p_cr; - } else if (UNLIKELY(p_lf != NULL)) { - p = p_lf; - } else { - p = data + len; - } - --p; - - break; - } - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (UNLIKELY(!IS_NUM(ch))) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - parser->header_state = h_state; - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - h_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - h_state = h_transfer_encoding_chunked; - } - break; - - case h_matching_connection_token_start: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - h_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - h_state = h_matching_connection_close; - } else if (c == 'u') { - h_state = h_matching_connection_upgrade; - } else if (STRICT_TOKEN(c)) { - h_state = h_matching_connection_token; - } else if (c == ' ' || c == '\t') { - /* Skip lws */ - } else { - h_state = h_general; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - h_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(CLOSE)-2) { - h_state = h_connection_close; - } - break; - - /* looking for 'Connection: upgrade' */ - case h_matching_connection_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE) - 1 || - c != UPGRADE[parser->index]) { - h_state = h_matching_connection_token; - } else if (parser->index == sizeof(UPGRADE)-2) { - h_state = h_connection_upgrade; - } - break; - - case h_matching_connection_token: - if (ch == ',') { - h_state = h_matching_connection_token_start; - parser->index = 0; - } - break; - - case h_transfer_encoding_chunked: - if (ch != ' ') h_state = h_general; - break; - - case h_connection_keep_alive: - case h_connection_close: - case h_connection_upgrade: - if (ch == ',') { - if (h_state == h_connection_keep_alive) { - parser->flags |= F_CONNECTION_KEEP_ALIVE; - } else if (h_state == h_connection_close) { - parser->flags |= F_CONNECTION_CLOSE; - } else if (h_state == h_connection_upgrade) { - parser->flags |= F_CONNECTION_UPGRADE; - } - h_state = h_matching_connection_token_start; - parser->index = 0; - } else if (ch != ' ') { - h_state = h_matching_connection_token; - } - break; - - default: - UPDATE_STATE(s_header_value); - h_state = h_general; - break; - } - } - parser->header_state = h_state; - - COUNT_HEADER_SIZE(p - start); - - if (p == data + len) - --p; - break; - } - - case s_header_almost_done: - { - if (UNLIKELY(ch != LF)) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - UPDATE_STATE(s_header_value_lws); - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') { - UPDATE_STATE(s_header_value_start); - REEXECUTE(); - } - - /* finished the header */ - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - default: - break; - } - - UPDATE_STATE(s_header_field_start); - REEXECUTE(); - } - - case s_header_value_discard_ws_almost_done: - { - STRICT_CHECK(ch != LF); - UPDATE_STATE(s_header_value_discard_lws); - break; - } - - case s_header_value_discard_lws: - { - if (ch == ' ' || ch == '\t') { - UPDATE_STATE(s_header_value_discard_ws); - break; - } else { - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_connection_upgrade: - parser->flags |= F_CONNECTION_UPGRADE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - /* header value was empty */ - MARK(header_value); - UPDATE_STATE(s_header_field_start); - CALLBACK_DATA_NOADVANCE(header_value); - REEXECUTE(); - } - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - UPDATE_STATE(s_message_done); - CALLBACK_NOTIFY_NOADVANCE(chunk_complete); - REEXECUTE(); - } - - /* Cannot use chunked encoding and a content-length header together - per the HTTP specification. */ - if ((parser->flags & F_CHUNKED) && - (parser->flags & F_CONTENTLENGTH)) { - SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); - goto error; - } - - UPDATE_STATE(s_headers_done); - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) == - (F_UPGRADE | F_CONNECTION_UPGRADE) || - parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 2: - parser->upgrade = 1; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - RETURN(p - data); /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - RETURN(p - data); - } - - REEXECUTE(); - } - - case s_headers_done: - { - int hasBody; - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - hasBody = parser->flags & F_CHUNKED || - (parser->content_length > 0 && parser->content_length != ULLONG_MAX); - if (parser->upgrade && (parser->method == HTTP_CONNECT || - (parser->flags & F_SKIPBODY) || !hasBody)) { - /* Exit, the rest of the message is in a different protocol. */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - RETURN((p - data) + 1); - } - - if (parser->flags & F_SKIPBODY) { - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - UPDATE_STATE(s_chunk_size_start); - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - UPDATE_STATE(s_body_identity); - } else { - if (!http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - UPDATE_STATE(s_body_identity_eof); - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - UPDATE_STATE(s_message_done); - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - REEXECUTE(); - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - UPDATE_STATE(NEW_MESSAGE()); - CALLBACK_NOTIFY(message_complete); - if (parser->upgrade) { - /* Exit, the rest of the message is in a different protocol. */ - RETURN((p - data) + 1); - } - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (UNLIKELY(unhex_val == -1)) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - UPDATE_STATE(s_chunk_size); - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - UPDATE_STATE(s_chunk_parameters); - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? Test against a conservative limit for simplicity. */ - if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this shit. TODO check for overflow */ - if (ch == CR) { - UPDATE_STATE(s_chunk_size_almost_done); - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - UPDATE_STATE(s_header_field_start); - } else { - UPDATE_STATE(s_chunk_data); - } - CALLBACK_NOTIFY(chunk_header); - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - UPDATE_STATE(s_chunk_data_almost_done); - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - UPDATE_STATE(s_chunk_data_done); - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - UPDATE_STATE(s_chunk_size_start); - CALLBACK_NOTIFY(chunk_complete); - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0) + - (status_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - CALLBACK_DATA_NOADVANCE(status); - - RETURN(len); - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - RETURN(p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -void -http_parser_settings_init(http_parser_settings *settings) -{ - memset(settings, 0, sizeof(*settings)); -} - -const char * -http_errno_name(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':' || ch == '.') { - return s_http_host_v6; - } - - if (s == s_http_host_v6 && ch == '%') { - return s_http_host_v6_zone_start; - } - break; - - case s_http_host_v6_zone: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_zone_start: - /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ - if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || - ch == '~') { - return s_http_host_v6_zone; - } - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - assert(u->field_set & (1 << UF_HOST)); - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = p - buf; - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = p - buf ; - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_host_v6_zone_start: - case s_http_host_v6_zone: - case s_http_host_port_start: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -void -http_parser_url_init(struct http_parser_url *u) { - memset(u, 0, sizeof(*u)); -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = p - buf; - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & (1 << UF_SCHEMA)) && - (u->field_set & (1 << UF_HOST)) == 0) { - return 1; - } - - if (u->field_set & (1 << UF_HOST)) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} - -unsigned long -http_parser_version(void) { - return HTTP_PARSER_VERSION_MAJOR * 0x10000 | - HTTP_PARSER_VERSION_MINOR * 0x00100 | - HTTP_PARSER_VERSION_PATCH * 0x00001; -} diff --git a/ext/http-parser/http_parser.h b/ext/http-parser/http_parser.h deleted file mode 100644 index 45c72a07..00000000 --- a/ext/http-parser/http_parser.h +++ /dev/null @@ -1,432 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. 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. - */ -#ifndef http_parser_h -#define http_parser_h -#ifdef __cplusplus -extern "C" { -#endif - -/* Also update SONAME in the Makefile whenever you change these. */ -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 7 -#define HTTP_PARSER_VERSION_PATCH 1 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && \ - (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) -#include -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed. If the macro is not defined - * before including this header then the default is used. To - * change the maximum header size, define the macro in the build - * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove - * the effective limit on the size of the header, define the macro - * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) - */ -#ifndef HTTP_MAX_HEADER_SIZE -# define HTTP_MAX_HEADER_SIZE (80*1024) -#endif - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * Returning `2` from on_headers_complete will tell parser that it should not - * expect neither a body nor any futher responses on this connection. This is - * useful for handling responses to a CONNECT request which may not contain - * `Upgrade` or `Connection: upgrade` headers. - * - * http_data_cb does not return data chunks. It will be called arbitrarily - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Status Codes */ -#define HTTP_STATUS_MAP(XX) \ - XX(100, CONTINUE, Continue) \ - XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ - XX(102, PROCESSING, Processing) \ - XX(200, OK, OK) \ - XX(201, CREATED, Created) \ - XX(202, ACCEPTED, Accepted) \ - XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ - XX(204, NO_CONTENT, No Content) \ - XX(205, RESET_CONTENT, Reset Content) \ - XX(206, PARTIAL_CONTENT, Partial Content) \ - XX(207, MULTI_STATUS, Multi-Status) \ - XX(208, ALREADY_REPORTED, Already Reported) \ - XX(226, IM_USED, IM Used) \ - XX(300, MULTIPLE_CHOICES, Multiple Choices) \ - XX(301, MOVED_PERMANENTLY, Moved Permanently) \ - XX(302, FOUND, Found) \ - XX(303, SEE_OTHER, See Other) \ - XX(304, NOT_MODIFIED, Not Modified) \ - XX(305, USE_PROXY, Use Proxy) \ - XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ - XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ - XX(400, BAD_REQUEST, Bad Request) \ - XX(401, UNAUTHORIZED, Unauthorized) \ - XX(402, PAYMENT_REQUIRED, Payment Required) \ - XX(403, FORBIDDEN, Forbidden) \ - XX(404, NOT_FOUND, Not Found) \ - XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ - XX(406, NOT_ACCEPTABLE, Not Acceptable) \ - XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ - XX(408, REQUEST_TIMEOUT, Request Timeout) \ - XX(409, CONFLICT, Conflict) \ - XX(410, GONE, Gone) \ - XX(411, LENGTH_REQUIRED, Length Required) \ - XX(412, PRECONDITION_FAILED, Precondition Failed) \ - XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ - XX(414, URI_TOO_LONG, URI Too Long) \ - XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ - XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ - XX(417, EXPECTATION_FAILED, Expectation Failed) \ - XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ - XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ - XX(423, LOCKED, Locked) \ - XX(424, FAILED_DEPENDENCY, Failed Dependency) \ - XX(426, UPGRADE_REQUIRED, Upgrade Required) \ - XX(428, PRECONDITION_REQUIRED, Precondition Required) \ - XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ - XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ - XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ - XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ - XX(501, NOT_IMPLEMENTED, Not Implemented) \ - XX(502, BAD_GATEWAY, Bad Gateway) \ - XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ - XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ - XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ - XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ - XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ - XX(508, LOOP_DETECTED, Loop Detected) \ - XX(510, NOT_EXTENDED, Not Extended) \ - XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ - -enum http_status - { -#define XX(num, name, string) HTTP_STATUS_##name = num, - HTTP_STATUS_MAP(XX) -#undef XX - }; - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* WebDAV */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - XX(16, BIND, BIND) \ - XX(17, REBIND, REBIND) \ - XX(18, UNBIND, UNBIND) \ - XX(19, ACL, ACL) \ - /* subversion */ \ - XX(20, REPORT, REPORT) \ - XX(21, MKACTIVITY, MKACTIVITY) \ - XX(22, CHECKOUT, CHECKOUT) \ - XX(23, MERGE, MERGE) \ - /* upnp */ \ - XX(24, MSEARCH, M-SEARCH) \ - XX(25, NOTIFY, NOTIFY) \ - XX(26, SUBSCRIBE, SUBSCRIBE) \ - XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(28, PATCH, PATCH) \ - XX(29, PURGE, PURGE) \ - /* CalDAV */ \ - XX(30, MKCALENDAR, MKCALENDAR) \ - /* RFC-2068, section 19.6.1.2 */ \ - XX(31, LINK, LINK) \ - XX(32, UNLINK, UNLINK) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_CONNECTION_UPGRADE = 1 << 3 - , F_TRAILING = 1 << 4 - , F_UPGRADE = 1 << 5 - , F_SKIPBODY = 1 << 6 - , F_CONTENTLENGTH = 1 << 7 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - XX(CB_status, "the on_status callback failed") \ - XX(CB_chunk_header, "the on_chunk_header callback failed") \ - XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(UNEXPECTED_CONTENT_LENGTH, \ - "unexpected content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 7; /* enum state from http_parser.c */ - unsigned int header_state : 7; /* enum header_state from http_parser.c */ - unsigned int index : 7; /* index into current matcher */ - unsigned int lenient_http_headers : 1; - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned int status_code : 16; /* responses only */ - unsigned int method : 8; /* requests only */ - unsigned int http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned int upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_data_cb on_status; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; - /* When on_chunk_header is called, the current chunk length is stored - * in parser->content_length. - */ - http_cb on_chunk_header; - http_cb on_chunk_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -/* Returns the library version. Bits 16-23 contain the major version number, - * bits 8-15 the minor version number and bits 0-7 the patch level. - * Usage example: - * - * unsigned long version = http_parser_version(); - * unsigned major = (version >> 16) & 255; - * unsigned minor = (version >> 8) & 255; - * unsigned patch = version & 255; - * printf("http_parser v%u.%u.%u\n", major, minor, patch); - */ -unsigned long http_parser_version(void); - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -/* Initialize http_parser_settings members to 0 - */ -void http_parser_settings_init(http_parser_settings *settings); - - -/* Executes the parser. Returns number of parsed bytes. Sets - * `parser->http_errno` on error. */ -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Initialize all http_parser_url members to 0 */ -void http_parser_url_init(struct http_parser_url *u); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/ext/inja/README.md b/ext/inja/README.md deleted file mode 100644 index 9d66a2c2..00000000 --- a/ext/inja/README.md +++ /dev/null @@ -1,391 +0,0 @@ -[
](https://github.com/pantor/inja/releases) - -

- - CI Status - - - - Documentation Status - - - - - - - - Github Releases - - - - Github Issues - - - - GitHub License - -

- -Inja is a template engine for modern C++, loosely inspired by [jinja](http://jinja.pocoo.org) for python. It has an easy and yet powerful template syntax with all variables, loops, conditions, includes, callbacks, and comments you need, nested and combined as you like. Inja uses the wonderful [json](https://github.com/nlohmann/json) library by nlohmann for data input. Most importantly, inja needs only two header files, which is (nearly) as trivial as integration in C++ can get. Of course, everything is tested on all relevant compilers. Here is what it looks like: - -```.cpp -json data; -data["name"] = "world"; - -inja::render("Hello {{ name }}!", data); // Returns "Hello world!" -``` - -## Integration - -Inja is a headers only library, which can be downloaded from the [releases](https://github.com/pantor/inja/releases) or directly from the `include/` or `single_include/` folder. Inja uses `nlohmann/json.hpp` (>= v3.8.0) as its single dependency, so make sure it can be included from `inja.hpp`. json can be downloaded [here](https://github.com/nlohmann/json/releases). Then integration is as easy as: - -```.cpp -#include - -// Just for convenience -using namespace inja; -``` - -If you are using the [Meson Build System](http://mesonbuild.com), then you can wrap this repository as a subproject. - -If you are using [Conan](https://conan.io) to manage your dependencies, have a look at [this repository](https://github.com/DEGoodmanWilson/conan-inja). Please file issues [here](https://github.com/DEGoodmanWilson/conan-inja/issues) if you experience problems with the packages. - -You can also integrate inja in your project using [Hunter](https://github.com/cpp-pm/hunter), a package manager for C++. - -If you are using [vcpkg](https://github.com/Microsoft/vcpkg) on your project for external dependencies, then you can use the [inja package](https://github.com/Microsoft/vcpkg/tree/master/ports/inja). Please see the vcpkg project for any issues regarding the packaging. - -If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install pantor/inja`. A specific version can be installed with `cget install pantor/inja@v2.1.0`. - -On macOS, you can install inja via [Homebrew](https://formulae.brew.sh/formula/inja#default) and `brew install inja`. - -If you are using [conda](https://docs.conda.io/en/latest/), you can install the latest version from [conda-forge](https://anaconda.org/conda-forge/inja) with `conda install -c conda-forge inja`. - -## Tutorial - -This tutorial will give you an idea how to use inja. It will explain the most important concepts and give practical advices using examples and executable code. Beside this tutorial, you may check out the [documentation](https://pantor.github.io/inja). - -### Template Rendering - -The basic template rendering takes a template as a `std::string` and a `json` object for all data. It returns the rendered template as an `std::string`. - -```.cpp -json data; -data["name"] = "world"; - -render("Hello {{ name }}!", data); // Returns std::string "Hello world!" -render_to(std::cout, "Hello {{ name }}!", data); // Writes "Hello world!" to stream -``` - -For more advanced usage, an environment is recommended. -```.cpp -Environment env; - -// Render a string with json data -std::string result = env.render("Hello {{ name }}!", data); // "Hello world!" - -// Or directly read a template file -Template temp = env.parse_template("./templates/greeting.txt"); -std::string result = env.render(temp, data); // "Hello world!" - -data["name"] = "Inja"; -std::string result = env.render(temp, data); // "Hello Inja!" - -// Or read the template file (and/or the json file) directly from the environment -result = env.render_file("./templates/greeting.txt", data); -result = env.render_file_with_json_file("./templates/greeting.txt", "./data.json"); - -// Or write a rendered template file -env.write(temp, data, "./result.txt"); -env.write_with_json_file("./templates/greeting.txt", "./data.json", "./result.txt"); -``` - -The environment class can be configured to your needs. -```.cpp -// With default settings -Environment env_default; - -// With global path to template files and where files will be saved -Environment env_1 {"../path/templates/"}; - -// With separate input and output path -Environment env_2 {"../path/templates/", "../path/results/"}; - -// With other opening and closing strings (here the defaults) -env.set_expression("{{", "}}"); // Expressions -env.set_comment("{#", "#}"); // Comments -env.set_statement("{%", "%}"); // Statements {% %} for many things, see below -env.set_line_statement("##"); // Line statements ## (just an opener) -``` - -### Variables - -Variables are rendered within the `{{ ... }}` expressions. -```.cpp -json data; -data["neighbour"] = "Peter"; -data["guests"] = {"Jeff", "Tom", "Patrick"}; -data["time"]["start"] = 16; -data["time"]["end"] = 22; - -// Indexing in array -render("{{ guests.1 }}", data); // "Tom" - -// Objects -render("{{ time.start }} to {{ time.end + 1 }}pm", data); // "16 to 23pm" -``` -If no variable is found, valid JSON is printed directly, otherwise an `inja::RenderError` is thrown. - -### Statements - -Statements can be written either with the `{% ... %}` syntax or the `##` syntax for entire lines. Note that `##` needs to start the line without indentation. The most important statements are loops, conditions and file includes. All statements can be nested. - -#### Loops - -```.cpp -// Combining loops and line statements -render(R"(Guest List: -## for guest in guests - {{ loop.index1 }}: {{ guest }} -## endfor )", data) - -/* Guest List: - 1: Jeff - 2: Tom - 3: Patrick */ -``` -In a loop, the special variables `loop.index (number)`, `loop.index1 (number)`, `loop.is_first (boolean)` and `loop.is_last (boolean)` are defined. In nested loops, the parent loop variables are available e.g. via `loop.parent.index`. You can also iterate over objects like `{% for key, value in time %}`. - -#### Conditions - -Conditions support the typical if, else if and else statements. Following conditions are for example possible: -```.cpp -// Standard comparisons with a variable -render("{% if time.hour >= 20 %}Serve{% else if time.hour >= 18 %}Make{% endif %} dinner.", data); // Serve dinner. - -// Variable in list -render("{% if neighbour in guests %}Turn up the music!{% endif %}", data); // Turn up the music! - -// Logical operations -render("{% if guest_count < (3+2) and all_tired %}Sleepy...{% else %}Keep going...{% endif %}", data); // Sleepy... - -// Negations -render("{% if not guest_count %}The End{% endif %}", data); // The End -``` - -#### Includes - -You can either include other in-memory templates or from the file system. -```.cpp -// To include in-memory templates, add them to the environment first -inja::Template content_template = env.parse("Hello {{ neighbour }}!"); -env.include_template("content", content_template); -env.render("Content: {% include \"content\" %}", data); // "Content: Hello Peter!" - -// Other template files are included relative from the current file location -render("{% include \"footer.html\" %}", data); -``` -If a corresponding template could not be found in the file system, the *include callback* is called: -```.cpp -// The callback takes the current path and the wanted include name and returns a template -env.set_include_callback([&env](const std::string& path, const std::string& template_name) { - return env.parse("Hello {{ neighbour }} from " + template_name); -}); - -// You can disable to search for templates in the file system via -env.set_search_included_templates_in_files(false); -``` - -Inja will throw an `inja::RenderError` if an included file is not found and no callback is specified. To disable this error, you can call `env.set_throw_at_missing_includes(false)`. - -#### Assignments - -Variables can also be defined within the template using the set statment. -```.cpp -render("{% set new_hour=23 %}{{ new_hour }}pm", data); // "23pm" -render("{% set time.start=18 %}{{ time.start }}pm", data); // using json pointers -``` - -Assignments only set the value within the rendering context; they do not modify the json object passed into the `render` call. - -### Functions - -A few functions are implemented within the inja template syntax. They can be called with -```.cpp -// Upper and lower function, for string cases -render("Hello {{ upper(neighbour) }}!", data); // "Hello PETER!" -render("Hello {{ lower(neighbour) }}!", data); // "Hello peter!" - -// Range function, useful for loops -render("{% for i in range(4) %}{{ loop.index1 }}{% endfor %}", data); // "1234" -render("{% for i in range(3) %}{{ at(guests, i) }} {% endfor %}", data); // "Jeff Tom Patrick " - -// Length function (please don't combine with range, use list directly...) -render("I count {{ length(guests) }} guests.", data); // "I count 3 guests." - -// Get first and last element in a list -render("{{ first(guests) }} was first.", data); // "Jeff was first." -render("{{ last(guests) }} was last.", data); // "Patir was last." - -// Sort a list -render("{{ sort([3,2,1]) }}", data); // "[1,2,3]" -render("{{ sort(guests) }}", data); // "[\"Jeff\", \"Patrick\", \"Tom\"]" - -// Join a list with a separator -render("{{ join([1,2,3], \" + \") }}", data); // "1 + 2 + 3" -render("{{ join(guests, \", \") }}", data); // "Jeff, Patrick, Tom" - -// Round numbers to a given precision -render("{{ round(3.1415, 0) }}", data); // 3 -render("{{ round(3.1415, 3) }}", data); // 3.142 - -// Check if a value is odd, even or divisible by a number -render("{{ odd(42) }}", data); // false -render("{{ even(42) }}", data); // true -render("{{ divisibleBy(42, 7) }}", data); // true - -// Maximum and minimum values from a list -render("{{ max([1, 2, 3]) }}", data); // 3 -render("{{ min([-2.4, -1.2, 4.5]) }}", data); // -2.4 - -// Convert strings to numbers -render("{{ int(\"2\") == 2 }}", data); // true -render("{{ float(\"1.8\") > 2 }}", data); // false - -// Set default values if variables are not defined -render("Hello {{ default(neighbour, \"my friend\") }}!", data); // "Hello Peter!" -render("Hello {{ default(colleague, \"my friend\") }}!", data); // "Hello my friend!" - -// Access an objects value dynamically -render("{{ at(time, \"start\") }} to {{ time.end }}", data); // "16 to 22" - -// Check if a key exists in an object -render("{{ exists(\"guests\") }}", data); // "true" -render("{{ exists(\"city\") }}", data); // "false" -render("{{ existsIn(time, \"start\") }}", data); // "true" -render("{{ existsIn(time, neighbour) }}", data); // "false" - -// Check if a key is a specific type -render("{{ isString(neighbour) }}", data); // "true" -render("{{ isArray(guests) }}", data); // "true" -// Implemented type checks: isArray, isBoolean, isFloat, isInteger, isNumber, isObject, isString, -``` - -### Callbacks - -You can create your own and more complex functions with callbacks. These are implemented with `std::function`, so you can for example use C++ lambdas. Inja `Arguments` are a vector of json pointers. -```.cpp -Environment env; - -/* - * Callbacks are defined by its: - * - name, - * - (optional) number of arguments, - * - callback function. - */ -env.add_callback("double", 1, [](Arguments& args) { - int number = args.at(0)->get(); // Adapt the index and type of the argument - return 2 * number; -}); - -// You can then use a callback like a regular function -env.render("{{ double(16) }}", data); // "32" - -// Inja falls back to variadic callbacks if the number of expected arguments is omitted. -env.add_callback("argmax", [](Arguments& args) { - auto result = std::max_element(args.begin(), args.end(), [](const json* a, const json* b) { return *a < *b;}); - return std::distance(args.begin(), result); -}); -env.render("{{ argmax(4, 2, 6) }}", data); // "2" -env.render("{{ argmax(0, 2, 6, 8, 3) }}", data); // "3" - -// A callback without argument can be used like a dynamic variable: -std::string greet = "Hello"; -env.add_callback("double-greetings", 0, [greet](Arguments args) { - return greet + " " + greet + "!"; -}); -env.render("{{ double-greetings }}", data); // "Hello Hello!" -``` -You can also add a void callback without return variable, e.g. for debugging: -```.cpp -env.add_void_callback("log", 1, [greet](Arguments args) { - std::cout << "logging: " << args[0] << std::endl; -}); -env.render("{{ log(neighbour) }}", data); // Prints nothing to result, only to cout... -``` - -### Template Inheritance - -Template inheritance allows you to build a base *skeleton* template that contains all the common elements and defines blocks that child templates can override. Lets show an example: The base template -```.html - - - - {% block head %} - - {% block title %}{% endblock %} - My Webpage - {% endblock %} - - -
{% block content %}{% endblock %}
- - -``` -contains three `blocks` that child templates can fill in. The child template -```.html -{% extends "base.html" %} -{% block title %}Index{% endblock %} -{% block head %} - {{ super() }} - -{% endblock %} -{% block content %} -

Index

-

- Welcome to my blog! -

-{% endblock %} -``` -calls a parent template with the `extends` keyword; it should be the first element in the template. It is possible to render the contents of the parent block by calling `super()`. In the case of multiple levels of `{% extends %}`, super references may be called with an argument (e.g. `super(2)`) to skip levels in the inheritance tree. - -### Whitespace Control - -In the default configuration, no whitespace is removed while rendering the file. To support a more readable template style, you can configure the environment to control whitespaces before and after a statement automatically. While enabling `set_trim_blocks` removes the first newline after a statement, `set_lstrip_blocks` strips tabs and spaces from the beginning of a line to the start of a block. - -```.cpp -Environment env; -env.set_trim_blocks(true); -env.set_lstrip_blocks(true); -``` - -With both `trim_blocks` and `lstrip_blocks` enabled, you can put statements on their own lines. Furthermore, you can also strip whitespaces for both statements and expressions by hand. If you add a minus sign (`-`) to the start or end, the whitespaces before or after that block will be removed: - -```.cpp -render("Hello {{- name -}} !", data); // "Hello Inja!" -render("{% if neighbour in guests -%} I was there{% endif -%} !", data); // Renders without any whitespaces -``` - -Stripping behind a statement or expression also removes any newlines. - -### Comments - -Comments can be written with the `{# ... #}` syntax. -```.cpp -render("Hello{# Todo #}!", data); // "Hello!" -``` - -### Exceptions - -Inja uses exceptions to handle ill-formed template input. However, exceptions can be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `INJA_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. - - -## Supported compilers - -Inja uses the `string_view` feature of the C++17 STL. Currently, the following compilers are tested: - -- GCC 7 - 11 (and possibly later) -- Clang 5 - 12 (and possibly later) -- Microsoft Visual C++ 2017 15.0 - 2022 (and possibly later) - -A list of supported compiler / os versions can be found in the [CI definition](https://github.com/pantor/inja/blob/master/.github/workflows/ci.yml). diff --git a/ext/inja/inja.hpp b/ext/inja/inja.hpp deleted file mode 100644 index 5b469745..00000000 --- a/ext/inja/inja.hpp +++ /dev/null @@ -1,2949 +0,0 @@ -/* - ___ _ Version 3.3 - |_ _|_ __ (_) __ _ https://github.com/pantor/inja - | || '_ \ | |/ _` | Licensed under the MIT License . - | || | | || | (_| | - |___|_| |_|/ |\__,_| Copyright (c) 2018-2021 Lars Berscheid - |__/ -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. -*/ - -#ifndef INCLUDE_INJA_INJA_HPP_ -#define INCLUDE_INJA_INJA_HPP_ - -#include - -namespace inja { -#ifndef INJA_DATA_TYPE -using json = nlohmann::json; -#else -using json = INJA_DATA_TYPE; -#endif -} // namespace inja - -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(INJA_NOEXCEPTION) -#ifndef INJA_THROW -#define INJA_THROW(exception) throw exception -#endif -#else -#include -#ifndef INJA_THROW -#define INJA_THROW(exception) \ - std::abort(); \ - std::ignore = exception -#endif -#ifndef INJA_NOEXCEPTION -#define INJA_NOEXCEPTION -#endif -#endif - -// #include "environment.hpp" -#ifndef INCLUDE_INJA_ENVIRONMENT_HPP_ -#define INCLUDE_INJA_ENVIRONMENT_HPP_ - -#include -#include -#include -#include -#include -#include - -// #include "config.hpp" -#ifndef INCLUDE_INJA_CONFIG_HPP_ -#define INCLUDE_INJA_CONFIG_HPP_ - -#include -#include - -// #include "template.hpp" -#ifndef INCLUDE_INJA_TEMPLATE_HPP_ -#define INCLUDE_INJA_TEMPLATE_HPP_ - -#include -#include -#include -#include - -// #include "node.hpp" -#ifndef INCLUDE_INJA_NODE_HPP_ -#define INCLUDE_INJA_NODE_HPP_ - -#include -#include -#include - -// #include "function_storage.hpp" -#ifndef INCLUDE_INJA_FUNCTION_STORAGE_HPP_ -#define INCLUDE_INJA_FUNCTION_STORAGE_HPP_ - -#include -#include - -namespace inja { - -using Arguments = std::vector; -using CallbackFunction = std::function; -using VoidCallbackFunction = std::function; - -/*! - * \brief Class for builtin functions and user-defined callbacks. - */ -class FunctionStorage { -public: - enum class Operation { - Not, - And, - Or, - In, - Equal, - NotEqual, - Greater, - GreaterEqual, - Less, - LessEqual, - Add, - Subtract, - Multiplication, - Division, - Power, - Modulo, - AtId, - At, - Default, - DivisibleBy, - Even, - Exists, - ExistsInObject, - First, - Float, - Int, - IsArray, - IsBoolean, - IsFloat, - IsInteger, - IsNumber, - IsObject, - IsString, - Last, - Length, - Lower, - Max, - Min, - Odd, - Range, - Round, - Sort, - Upper, - Super, - Join, - Callback, - ParenLeft, - ParenRight, - None, - }; - - struct FunctionData { - explicit FunctionData(const Operation& op, const CallbackFunction& cb = CallbackFunction {}): operation(op), callback(cb) {} - const Operation operation; - const CallbackFunction callback; - }; - -private: - const int VARIADIC {-1}; - - std::map, FunctionData> function_storage = { - {std::make_pair("at", 2), FunctionData {Operation::At}}, - {std::make_pair("default", 2), FunctionData {Operation::Default}}, - {std::make_pair("divisibleBy", 2), FunctionData {Operation::DivisibleBy}}, - {std::make_pair("even", 1), FunctionData {Operation::Even}}, - {std::make_pair("exists", 1), FunctionData {Operation::Exists}}, - {std::make_pair("existsIn", 2), FunctionData {Operation::ExistsInObject}}, - {std::make_pair("first", 1), FunctionData {Operation::First}}, - {std::make_pair("float", 1), FunctionData {Operation::Float}}, - {std::make_pair("int", 1), FunctionData {Operation::Int}}, - {std::make_pair("isArray", 1), FunctionData {Operation::IsArray}}, - {std::make_pair("isBoolean", 1), FunctionData {Operation::IsBoolean}}, - {std::make_pair("isFloat", 1), FunctionData {Operation::IsFloat}}, - {std::make_pair("isInteger", 1), FunctionData {Operation::IsInteger}}, - {std::make_pair("isNumber", 1), FunctionData {Operation::IsNumber}}, - {std::make_pair("isObject", 1), FunctionData {Operation::IsObject}}, - {std::make_pair("isString", 1), FunctionData {Operation::IsString}}, - {std::make_pair("last", 1), FunctionData {Operation::Last}}, - {std::make_pair("length", 1), FunctionData {Operation::Length}}, - {std::make_pair("lower", 1), FunctionData {Operation::Lower}}, - {std::make_pair("max", 1), FunctionData {Operation::Max}}, - {std::make_pair("min", 1), FunctionData {Operation::Min}}, - {std::make_pair("odd", 1), FunctionData {Operation::Odd}}, - {std::make_pair("range", 1), FunctionData {Operation::Range}}, - {std::make_pair("round", 2), FunctionData {Operation::Round}}, - {std::make_pair("sort", 1), FunctionData {Operation::Sort}}, - {std::make_pair("upper", 1), FunctionData {Operation::Upper}}, - {std::make_pair("super", 0), FunctionData {Operation::Super}}, - {std::make_pair("super", 1), FunctionData {Operation::Super}}, - {std::make_pair("join", 2), FunctionData {Operation::Join}}, - }; - -public: - void add_builtin(std::string_view name, int num_args, Operation op) { - function_storage.emplace(std::make_pair(static_cast(name), num_args), FunctionData {op}); - } - - void add_callback(std::string_view name, int num_args, const CallbackFunction& callback) { - function_storage.emplace(std::make_pair(static_cast(name), num_args), FunctionData {Operation::Callback, callback}); - } - - FunctionData find_function(std::string_view name, int num_args) const { - auto it = function_storage.find(std::make_pair(static_cast(name), num_args)); - if (it != function_storage.end()) { - return it->second; - - // Find variadic function - } else if (num_args > 0) { - it = function_storage.find(std::make_pair(static_cast(name), VARIADIC)); - if (it != function_storage.end()) { - return it->second; - } - } - - return FunctionData {Operation::None}; - } -}; - -} // namespace inja - -#endif // INCLUDE_INJA_FUNCTION_STORAGE_HPP_ - -// #include "utils.hpp" -#ifndef INCLUDE_INJA_UTILS_HPP_ -#define INCLUDE_INJA_UTILS_HPP_ - -#include -#include -#include -#include -#include - -// #include "exceptions.hpp" -#ifndef INCLUDE_INJA_EXCEPTIONS_HPP_ -#define INCLUDE_INJA_EXCEPTIONS_HPP_ - -#include -#include - -namespace inja { - -struct SourceLocation { - size_t line; - size_t column; -}; - -struct InjaError : public std::runtime_error { - const std::string type; - const std::string message; - - const SourceLocation location; - - explicit InjaError(const std::string& type, const std::string& message) - : std::runtime_error("[inja.exception." + type + "] " + message), type(type), message(message), location({0, 0}) {} - - explicit InjaError(const std::string& type, const std::string& message, SourceLocation location) - : std::runtime_error("[inja.exception." + type + "] (at " + std::to_string(location.line) + ":" + std::to_string(location.column) + ") " + message), - type(type), message(message), location(location) {} -}; - -struct ParserError : public InjaError { - explicit ParserError(const std::string& message, SourceLocation location): InjaError("parser_error", message, location) {} -}; - -struct RenderError : public InjaError { - explicit RenderError(const std::string& message, SourceLocation location): InjaError("render_error", message, location) {} -}; - -struct FileError : public InjaError { - explicit FileError(const std::string& message): InjaError("file_error", message) {} - explicit FileError(const std::string& message, SourceLocation location): InjaError("file_error", message, location) {} -}; - -struct DataError : public InjaError { - explicit DataError(const std::string& message, SourceLocation location): InjaError("data_error", message, location) {} -}; - -} // namespace inja - -#endif // INCLUDE_INJA_EXCEPTIONS_HPP_ - - -namespace inja { - -namespace string_view { -inline std::string_view slice(std::string_view view, size_t start, size_t end) { - start = std::min(start, view.size()); - end = std::min(std::max(start, end), view.size()); - return view.substr(start, end - start); -} - -inline std::pair split(std::string_view view, char Separator) { - size_t idx = view.find(Separator); - if (idx == std::string_view::npos) { - return std::make_pair(view, std::string_view()); - } - return std::make_pair(slice(view, 0, idx), slice(view, idx + 1, std::string_view::npos)); -} - -inline bool starts_with(std::string_view view, std::string_view prefix) { - return (view.size() >= prefix.size() && view.compare(0, prefix.size(), prefix) == 0); -} -} // namespace string_view - -inline SourceLocation get_source_location(std::string_view content, size_t pos) { - // Get line and offset position (starts at 1:1) - auto sliced = string_view::slice(content, 0, pos); - std::size_t last_newline = sliced.rfind("\n"); - - if (last_newline == std::string_view::npos) { - return {1, sliced.length() + 1}; - } - - // Count newlines - size_t count_lines = 0; - size_t search_start = 0; - while (search_start <= sliced.size()) { - search_start = sliced.find("\n", search_start) + 1; - if (search_start == 0) { - break; - } - count_lines += 1; - } - - return {count_lines + 1, sliced.length() - last_newline}; -} - -inline void replace_substring(std::string& s, const std::string& f, const std::string& t) { - if (f.empty()) { - return; - } - for (auto pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} -} - -} // namespace inja - -#endif // INCLUDE_INJA_UTILS_HPP_ - - -namespace inja { - -class NodeVisitor; -class BlockNode; -class TextNode; -class ExpressionNode; -class LiteralNode; -class DataNode; -class FunctionNode; -class ExpressionListNode; -class StatementNode; -class ForStatementNode; -class ForArrayStatementNode; -class ForObjectStatementNode; -class IfStatementNode; -class IncludeStatementNode; -class ExtendsStatementNode; -class BlockStatementNode; -class SetStatementNode; - -class NodeVisitor { -public: - virtual ~NodeVisitor() = default; - - virtual void visit(const BlockNode& node) = 0; - virtual void visit(const TextNode& node) = 0; - virtual void visit(const ExpressionNode& node) = 0; - virtual void visit(const LiteralNode& node) = 0; - virtual void visit(const DataNode& node) = 0; - virtual void visit(const FunctionNode& node) = 0; - virtual void visit(const ExpressionListNode& node) = 0; - virtual void visit(const StatementNode& node) = 0; - virtual void visit(const ForStatementNode& node) = 0; - virtual void visit(const ForArrayStatementNode& node) = 0; - virtual void visit(const ForObjectStatementNode& node) = 0; - virtual void visit(const IfStatementNode& node) = 0; - virtual void visit(const IncludeStatementNode& node) = 0; - virtual void visit(const ExtendsStatementNode& node) = 0; - virtual void visit(const BlockStatementNode& node) = 0; - virtual void visit(const SetStatementNode& node) = 0; -}; - -/*! - * \brief Base node class for the abstract syntax tree (AST). - */ -class AstNode { -public: - virtual void accept(NodeVisitor& v) const = 0; - - size_t pos; - - AstNode(size_t pos): pos(pos) {} - virtual ~AstNode() {} -}; - -class BlockNode : public AstNode { -public: - std::vector> nodes; - - explicit BlockNode(): AstNode(0) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class TextNode : public AstNode { -public: - const size_t length; - - explicit TextNode(size_t pos, size_t length): AstNode(pos), length(length) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class ExpressionNode : public AstNode { -public: - explicit ExpressionNode(size_t pos): AstNode(pos) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class LiteralNode : public ExpressionNode { -public: - const json value; - - explicit LiteralNode(std::string_view data_text, size_t pos): ExpressionNode(pos), value(json::parse(data_text)) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class DataNode : public ExpressionNode { -public: - const std::string name; - const json::json_pointer ptr; - - static std::string convert_dot_to_ptr(std::string_view ptr_name) { - std::string result; - do { - std::string_view part; - std::tie(part, ptr_name) = string_view::split(ptr_name, '.'); - result.push_back('/'); - result.append(part.begin(), part.end()); - } while (!ptr_name.empty()); - return result; - } - - explicit DataNode(std::string_view ptr_name, size_t pos): ExpressionNode(pos), name(ptr_name), ptr(json::json_pointer(convert_dot_to_ptr(ptr_name))) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class FunctionNode : public ExpressionNode { - using Op = FunctionStorage::Operation; - -public: - enum class Associativity { - Left, - Right, - }; - - unsigned int precedence; - Associativity associativity; - - Op operation; - - std::string name; - int number_args; // Should also be negative -> -1 for unknown number - std::vector> arguments; - CallbackFunction callback; - - explicit FunctionNode(std::string_view name, size_t pos) - : ExpressionNode(pos), precedence(8), associativity(Associativity::Left), operation(Op::Callback), name(name), number_args(1) {} - explicit FunctionNode(Op operation, size_t pos): ExpressionNode(pos), operation(operation), number_args(1) { - switch (operation) { - case Op::Not: { - number_args = 1; - precedence = 4; - associativity = Associativity::Left; - } break; - case Op::And: { - number_args = 2; - precedence = 1; - associativity = Associativity::Left; - } break; - case Op::Or: { - number_args = 2; - precedence = 1; - associativity = Associativity::Left; - } break; - case Op::In: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::Equal: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::NotEqual: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::Greater: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::GreaterEqual: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::Less: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::LessEqual: { - number_args = 2; - precedence = 2; - associativity = Associativity::Left; - } break; - case Op::Add: { - number_args = 2; - precedence = 3; - associativity = Associativity::Left; - } break; - case Op::Subtract: { - number_args = 2; - precedence = 3; - associativity = Associativity::Left; - } break; - case Op::Multiplication: { - number_args = 2; - precedence = 4; - associativity = Associativity::Left; - } break; - case Op::Division: { - number_args = 2; - precedence = 4; - associativity = Associativity::Left; - } break; - case Op::Power: { - number_args = 2; - precedence = 5; - associativity = Associativity::Right; - } break; - case Op::Modulo: { - number_args = 2; - precedence = 4; - associativity = Associativity::Left; - } break; - case Op::AtId: { - number_args = 2; - precedence = 8; - associativity = Associativity::Left; - } break; - default: { - precedence = 1; - associativity = Associativity::Left; - } - } - } - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class ExpressionListNode : public AstNode { -public: - std::shared_ptr root; - - explicit ExpressionListNode(): AstNode(0) {} - explicit ExpressionListNode(size_t pos): AstNode(pos) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class StatementNode : public AstNode { -public: - StatementNode(size_t pos): AstNode(pos) {} - - virtual void accept(NodeVisitor& v) const = 0; -}; - -class ForStatementNode : public StatementNode { -public: - ExpressionListNode condition; - BlockNode body; - BlockNode* const parent; - - ForStatementNode(BlockNode* const parent, size_t pos): StatementNode(pos), parent(parent) {} - - virtual void accept(NodeVisitor& v) const = 0; -}; - -class ForArrayStatementNode : public ForStatementNode { -public: - const std::string value; - - explicit ForArrayStatementNode(const std::string& value, BlockNode* const parent, size_t pos): ForStatementNode(parent, pos), value(value) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class ForObjectStatementNode : public ForStatementNode { -public: - const std::string key; - const std::string value; - - explicit ForObjectStatementNode(const std::string& key, const std::string& value, BlockNode* const parent, size_t pos) - : ForStatementNode(parent, pos), key(key), value(value) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class IfStatementNode : public StatementNode { -public: - ExpressionListNode condition; - BlockNode true_statement; - BlockNode false_statement; - BlockNode* const parent; - - const bool is_nested; - bool has_false_statement {false}; - - explicit IfStatementNode(BlockNode* const parent, size_t pos): StatementNode(pos), parent(parent), is_nested(false) {} - explicit IfStatementNode(bool is_nested, BlockNode* const parent, size_t pos): StatementNode(pos), parent(parent), is_nested(is_nested) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class IncludeStatementNode : public StatementNode { -public: - const std::string file; - - explicit IncludeStatementNode(const std::string& file, size_t pos): StatementNode(pos), file(file) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -class ExtendsStatementNode : public StatementNode { -public: - const std::string file; - - explicit ExtendsStatementNode(const std::string& file, size_t pos): StatementNode(pos), file(file) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - }; -}; - -class BlockStatementNode : public StatementNode { -public: - const std::string name; - BlockNode block; - BlockNode* const parent; - - explicit BlockStatementNode(BlockNode* const parent, const std::string& name, size_t pos): StatementNode(pos), name(name), parent(parent) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - }; -}; - -class SetStatementNode : public StatementNode { -public: - const std::string key; - ExpressionListNode expression; - - explicit SetStatementNode(const std::string& key, size_t pos): StatementNode(pos), key(key) {} - - void accept(NodeVisitor& v) const { - v.visit(*this); - } -}; - -} // namespace inja - -#endif // INCLUDE_INJA_NODE_HPP_ - -// #include "statistics.hpp" -#ifndef INCLUDE_INJA_STATISTICS_HPP_ -#define INCLUDE_INJA_STATISTICS_HPP_ - -// #include "node.hpp" - - -namespace inja { - -/*! - * \brief A class for counting statistics on a Template. - */ -class StatisticsVisitor : public NodeVisitor { - void visit(const BlockNode& node) { - for (auto& n : node.nodes) { - n->accept(*this); - } - } - - void visit(const TextNode&) {} - void visit(const ExpressionNode&) {} - void visit(const LiteralNode&) {} - - void visit(const DataNode&) { - variable_counter += 1; - } - - void visit(const FunctionNode& node) { - for (auto& n : node.arguments) { - n->accept(*this); - } - } - - void visit(const ExpressionListNode& node) { - node.root->accept(*this); - } - - void visit(const StatementNode&) {} - void visit(const ForStatementNode&) {} - - void visit(const ForArrayStatementNode& node) { - node.condition.accept(*this); - node.body.accept(*this); - } - - void visit(const ForObjectStatementNode& node) { - node.condition.accept(*this); - node.body.accept(*this); - } - - void visit(const IfStatementNode& node) { - node.condition.accept(*this); - node.true_statement.accept(*this); - node.false_statement.accept(*this); - } - - void visit(const IncludeStatementNode&) {} - - void visit(const ExtendsStatementNode&) {} - - void visit(const BlockStatementNode& node) { - node.block.accept(*this); - } - - void visit(const SetStatementNode&) {} - -public: - unsigned int variable_counter; - - explicit StatisticsVisitor(): variable_counter(0) {} -}; - -} // namespace inja - -#endif // INCLUDE_INJA_STATISTICS_HPP_ - - -namespace inja { - -/*! - * \brief The main inja Template. - */ -struct Template { - BlockNode root; - std::string content; - std::map> block_storage; - - explicit Template() {} - explicit Template(const std::string& content): content(content) {} - - /// Return number of variables (total number, not distinct ones) in the template - int count_variables() { - auto statistic_visitor = StatisticsVisitor(); - root.accept(statistic_visitor); - return statistic_visitor.variable_counter; - } -}; - -using TemplateStorage = std::map; - -} // namespace inja - -#endif // INCLUDE_INJA_TEMPLATE_HPP_ - - -namespace inja { - -/*! - * \brief Class for lexer configuration. - */ -struct LexerConfig { - std::string statement_open {"{%"}; - std::string statement_open_no_lstrip {"{%+"}; - std::string statement_open_force_lstrip {"{%-"}; - std::string statement_close {"%}"}; - std::string statement_close_force_rstrip {"-%}"}; - std::string line_statement {"##"}; - std::string expression_open {"{{"}; - std::string expression_open_force_lstrip {"{{-"}; - std::string expression_close {"}}"}; - std::string expression_close_force_rstrip {"-}}"}; - std::string comment_open {"{#"}; - std::string comment_open_force_lstrip {"{#-"}; - std::string comment_close {"#}"}; - std::string comment_close_force_rstrip {"-#}"}; - std::string open_chars {"#{"}; - - bool trim_blocks {false}; - bool lstrip_blocks {false}; - - void update_open_chars() { - open_chars = ""; - if (open_chars.find(line_statement[0]) == std::string::npos) { - open_chars += line_statement[0]; - } - if (open_chars.find(statement_open[0]) == std::string::npos) { - open_chars += statement_open[0]; - } - if (open_chars.find(statement_open_no_lstrip[0]) == std::string::npos) { - open_chars += statement_open_no_lstrip[0]; - } - if (open_chars.find(statement_open_force_lstrip[0]) == std::string::npos) { - open_chars += statement_open_force_lstrip[0]; - } - if (open_chars.find(expression_open[0]) == std::string::npos) { - open_chars += expression_open[0]; - } - if (open_chars.find(expression_open_force_lstrip[0]) == std::string::npos) { - open_chars += expression_open_force_lstrip[0]; - } - if (open_chars.find(comment_open[0]) == std::string::npos) { - open_chars += comment_open[0]; - } - if (open_chars.find(comment_open_force_lstrip[0]) == std::string::npos) { - open_chars += comment_open_force_lstrip[0]; - } - } -}; - -/*! - * \brief Class for parser configuration. - */ -struct ParserConfig { - bool search_included_templates_in_files {true}; - - std::function include_callback; -}; - -/*! - * \brief Class for render configuration. - */ -struct RenderConfig { - bool throw_at_missing_includes {true}; -}; - -} // namespace inja - -#endif // INCLUDE_INJA_CONFIG_HPP_ - -// #include "function_storage.hpp" - -// #include "parser.hpp" -#ifndef INCLUDE_INJA_PARSER_HPP_ -#define INCLUDE_INJA_PARSER_HPP_ - -#include -#include -#include -#include -#include - -// #include "config.hpp" - -// #include "exceptions.hpp" - -// #include "function_storage.hpp" - -// #include "lexer.hpp" -#ifndef INCLUDE_INJA_LEXER_HPP_ -#define INCLUDE_INJA_LEXER_HPP_ - -#include -#include - -// #include "config.hpp" - -// #include "token.hpp" -#ifndef INCLUDE_INJA_TOKEN_HPP_ -#define INCLUDE_INJA_TOKEN_HPP_ - -#include -#include - -namespace inja { - -/*! - * \brief Helper-class for the inja Lexer. - */ -struct Token { - enum class Kind { - Text, - ExpressionOpen, // {{ - ExpressionClose, // }} - LineStatementOpen, // ## - LineStatementClose, // \n - StatementOpen, // {% - StatementClose, // %} - CommentOpen, // {# - CommentClose, // #} - Id, // this, this.foo - Number, // 1, 2, -1, 5.2, -5.3 - String, // "this" - Plus, // + - Minus, // - - Times, // * - Slash, // / - Percent, // % - Power, // ^ - Comma, // , - Dot, // . - Colon, // : - LeftParen, // ( - RightParen, // ) - LeftBracket, // [ - RightBracket, // ] - LeftBrace, // { - RightBrace, // } - Equal, // == - NotEqual, // != - GreaterThan, // > - GreaterEqual, // >= - LessThan, // < - LessEqual, // <= - Unknown, - Eof, - }; - - Kind kind {Kind::Unknown}; - std::string_view text; - - explicit constexpr Token() = default; - explicit constexpr Token(Kind kind, std::string_view text): kind(kind), text(text) {} - - std::string describe() const { - switch (kind) { - case Kind::Text: - return ""; - case Kind::LineStatementClose: - return ""; - case Kind::Eof: - return ""; - default: - return static_cast(text); - } - } -}; - -} // namespace inja - -#endif // INCLUDE_INJA_TOKEN_HPP_ - -// #include "utils.hpp" - - -namespace inja { - -/*! - * \brief Class for lexing an inja Template. - */ -class Lexer { - enum class State { - Text, - ExpressionStart, - ExpressionStartForceLstrip, - ExpressionBody, - LineStart, - LineBody, - StatementStart, - StatementStartNoLstrip, - StatementStartForceLstrip, - StatementBody, - CommentStart, - CommentStartForceLstrip, - CommentBody, - }; - - enum class MinusState { - Operator, - Number, - }; - - const LexerConfig& config; - - State state; - MinusState minus_state; - std::string_view m_in; - size_t tok_start; - size_t pos; - - Token scan_body(std::string_view close, Token::Kind closeKind, std::string_view close_trim = std::string_view(), bool trim = false) { - again: - // skip whitespace (except for \n as it might be a close) - if (tok_start >= m_in.size()) { - return make_token(Token::Kind::Eof); - } - const char ch = m_in[tok_start]; - if (ch == ' ' || ch == '\t' || ch == '\r') { - tok_start += 1; - goto again; - } - - // check for close - if (!close_trim.empty() && inja::string_view::starts_with(m_in.substr(tok_start), close_trim)) { - state = State::Text; - pos = tok_start + close_trim.size(); - const Token tok = make_token(closeKind); - skip_whitespaces_and_newlines(); - return tok; - } - - if (inja::string_view::starts_with(m_in.substr(tok_start), close)) { - state = State::Text; - pos = tok_start + close.size(); - const Token tok = make_token(closeKind); - if (trim) { - skip_whitespaces_and_first_newline(); - } - return tok; - } - - // skip \n - if (ch == '\n') { - tok_start += 1; - goto again; - } - - pos = tok_start + 1; - if (std::isalpha(ch)) { - minus_state = MinusState::Operator; - return scan_id(); - } - - const MinusState current_minus_state = minus_state; - if (minus_state == MinusState::Operator) { - minus_state = MinusState::Number; - } - - switch (ch) { - case '+': - return make_token(Token::Kind::Plus); - case '-': - if (current_minus_state == MinusState::Operator) { - return make_token(Token::Kind::Minus); - } - return scan_number(); - case '*': - return make_token(Token::Kind::Times); - case '/': - return make_token(Token::Kind::Slash); - case '^': - return make_token(Token::Kind::Power); - case '%': - return make_token(Token::Kind::Percent); - case '.': - return make_token(Token::Kind::Dot); - case ',': - return make_token(Token::Kind::Comma); - case ':': - return make_token(Token::Kind::Colon); - case '(': - return make_token(Token::Kind::LeftParen); - case ')': - minus_state = MinusState::Operator; - return make_token(Token::Kind::RightParen); - case '[': - return make_token(Token::Kind::LeftBracket); - case ']': - minus_state = MinusState::Operator; - return make_token(Token::Kind::RightBracket); - case '{': - return make_token(Token::Kind::LeftBrace); - case '}': - minus_state = MinusState::Operator; - return make_token(Token::Kind::RightBrace); - case '>': - if (pos < m_in.size() && m_in[pos] == '=') { - pos += 1; - return make_token(Token::Kind::GreaterEqual); - } - return make_token(Token::Kind::GreaterThan); - case '<': - if (pos < m_in.size() && m_in[pos] == '=') { - pos += 1; - return make_token(Token::Kind::LessEqual); - } - return make_token(Token::Kind::LessThan); - case '=': - if (pos < m_in.size() && m_in[pos] == '=') { - pos += 1; - return make_token(Token::Kind::Equal); - } - return make_token(Token::Kind::Unknown); - case '!': - if (pos < m_in.size() && m_in[pos] == '=') { - pos += 1; - return make_token(Token::Kind::NotEqual); - } - return make_token(Token::Kind::Unknown); - case '\"': - return scan_string(); - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - minus_state = MinusState::Operator; - return scan_number(); - case '_': - case '@': - case '$': - minus_state = MinusState::Operator; - return scan_id(); - default: - return make_token(Token::Kind::Unknown); - } - } - - Token scan_id() { - for (;;) { - if (pos >= m_in.size()) { - break; - } - const char ch = m_in[pos]; - if (!std::isalnum(ch) && ch != '.' && ch != '/' && ch != '_' && ch != '-') { - break; - } - pos += 1; - } - return make_token(Token::Kind::Id); - } - - Token scan_number() { - for (;;) { - if (pos >= m_in.size()) { - break; - } - const char ch = m_in[pos]; - // be very permissive in lexer (we'll catch errors when conversion happens) - if (!(std::isdigit(ch) || ch == '.' || ch == 'e' || ch == 'E' || (ch == '+' && (pos == 0 || m_in[pos-1] == 'e' || m_in[pos-1] == 'E')) || (ch == '-' && (pos == 0 || m_in[pos-1] == 'e' || m_in[pos-1] == 'E')))) { - break; - } - pos += 1; - } - return make_token(Token::Kind::Number); - } - - Token scan_string() { - bool escape {false}; - for (;;) { - if (pos >= m_in.size()) { - break; - } - const char ch = m_in[pos++]; - if (ch == '\\') { - escape = true; - } else if (!escape && ch == m_in[tok_start]) { - break; - } else { - escape = false; - } - } - return make_token(Token::Kind::String); - } - - Token make_token(Token::Kind kind) const { - return Token(kind, string_view::slice(m_in, tok_start, pos)); - } - - void skip_whitespaces_and_newlines() { - if (pos < m_in.size()) { - while (pos < m_in.size() && (m_in[pos] == ' ' || m_in[pos] == '\t' || m_in[pos] == '\n' || m_in[pos] == '\r')) { - pos += 1; - } - } - } - - void skip_whitespaces_and_first_newline() { - if (pos < m_in.size()) { - while (pos < m_in.size() && (m_in[pos] == ' ' || m_in[pos] == '\t')) { - pos += 1; - } - } - - if (pos < m_in.size()) { - const char ch = m_in[pos]; - if (ch == '\n') { - pos += 1; - } else if (ch == '\r') { - pos += 1; - if (pos < m_in.size() && m_in[pos] == '\n') { - pos += 1; - } - } - } - } - - static std::string_view clear_final_line_if_whitespace(std::string_view text) { - std::string_view result = text; - while (!result.empty()) { - const char ch = result.back(); - if (ch == ' ' || ch == '\t') { - result.remove_suffix(1); - } else if (ch == '\n' || ch == '\r') { - break; - } else { - return text; - } - } - return result; - } - -public: - explicit Lexer(const LexerConfig& config): config(config), state(State::Text), minus_state(MinusState::Number) {} - - SourceLocation current_position() const { - return get_source_location(m_in, tok_start); - } - - void start(std::string_view input) { - m_in = input; - tok_start = 0; - pos = 0; - state = State::Text; - minus_state = MinusState::Number; - - // Consume byte order mark (BOM) for UTF-8 - if (inja::string_view::starts_with(m_in, "\xEF\xBB\xBF")) { - m_in = m_in.substr(3); - } - } - - Token scan() { - tok_start = pos; - - again: - if (tok_start >= m_in.size()) { - return make_token(Token::Kind::Eof); - } - - switch (state) { - default: - case State::Text: { - // fast-scan to first open character - const size_t open_start = m_in.substr(pos).find_first_of(config.open_chars); - if (open_start == std::string_view::npos) { - // didn't find open, return remaining text as text token - pos = m_in.size(); - return make_token(Token::Kind::Text); - } - pos += open_start; - - // try to match one of the opening sequences, and get the close - std::string_view open_str = m_in.substr(pos); - bool must_lstrip = false; - if (inja::string_view::starts_with(open_str, config.expression_open)) { - if (inja::string_view::starts_with(open_str, config.expression_open_force_lstrip)) { - state = State::ExpressionStartForceLstrip; - must_lstrip = true; - } else { - state = State::ExpressionStart; - } - } else if (inja::string_view::starts_with(open_str, config.statement_open)) { - if (inja::string_view::starts_with(open_str, config.statement_open_no_lstrip)) { - state = State::StatementStartNoLstrip; - } else if (inja::string_view::starts_with(open_str, config.statement_open_force_lstrip)) { - state = State::StatementStartForceLstrip; - must_lstrip = true; - } else { - state = State::StatementStart; - must_lstrip = config.lstrip_blocks; - } - } else if (inja::string_view::starts_with(open_str, config.comment_open)) { - if (inja::string_view::starts_with(open_str, config.comment_open_force_lstrip)) { - state = State::CommentStartForceLstrip; - must_lstrip = true; - } else { - state = State::CommentStart; - must_lstrip = config.lstrip_blocks; - } - } else if ((pos == 0 || m_in[pos - 1] == '\n') && inja::string_view::starts_with(open_str, config.line_statement)) { - state = State::LineStart; - } else { - pos += 1; // wasn't actually an opening sequence - goto again; - } - - std::string_view text = string_view::slice(m_in, tok_start, pos); - if (must_lstrip) { - text = clear_final_line_if_whitespace(text); - } - - if (text.empty()) { - goto again; // don't generate empty token - } - return Token(Token::Kind::Text, text); - } - case State::ExpressionStart: { - state = State::ExpressionBody; - pos += config.expression_open.size(); - return make_token(Token::Kind::ExpressionOpen); - } - case State::ExpressionStartForceLstrip: { - state = State::ExpressionBody; - pos += config.expression_open_force_lstrip.size(); - return make_token(Token::Kind::ExpressionOpen); - } - case State::LineStart: { - state = State::LineBody; - pos += config.line_statement.size(); - return make_token(Token::Kind::LineStatementOpen); - } - case State::StatementStart: { - state = State::StatementBody; - pos += config.statement_open.size(); - return make_token(Token::Kind::StatementOpen); - } - case State::StatementStartNoLstrip: { - state = State::StatementBody; - pos += config.statement_open_no_lstrip.size(); - return make_token(Token::Kind::StatementOpen); - } - case State::StatementStartForceLstrip: { - state = State::StatementBody; - pos += config.statement_open_force_lstrip.size(); - return make_token(Token::Kind::StatementOpen); - } - case State::CommentStart: { - state = State::CommentBody; - pos += config.comment_open.size(); - return make_token(Token::Kind::CommentOpen); - } - case State::CommentStartForceLstrip: { - state = State::CommentBody; - pos += config.comment_open_force_lstrip.size(); - return make_token(Token::Kind::CommentOpen); - } - case State::ExpressionBody: - return scan_body(config.expression_close, Token::Kind::ExpressionClose, config.expression_close_force_rstrip); - case State::LineBody: - return scan_body("\n", Token::Kind::LineStatementClose); - case State::StatementBody: - return scan_body(config.statement_close, Token::Kind::StatementClose, config.statement_close_force_rstrip, config.trim_blocks); - case State::CommentBody: { - // fast-scan to comment close - const size_t end = m_in.substr(pos).find(config.comment_close); - if (end == std::string_view::npos) { - pos = m_in.size(); - return make_token(Token::Kind::Eof); - } - - // Check for trim pattern - const bool must_rstrip = inja::string_view::starts_with(m_in.substr(pos + end - 1), config.comment_close_force_rstrip); - - // return the entire comment in the close token - state = State::Text; - pos += end + config.comment_close.size(); - Token tok = make_token(Token::Kind::CommentClose); - - if (must_rstrip || config.trim_blocks) { - skip_whitespaces_and_first_newline(); - } - return tok; - } - } - } - - const LexerConfig& get_config() const { - return config; - } -}; - -} // namespace inja - -#endif // INCLUDE_INJA_LEXER_HPP_ - -// #include "node.hpp" - -// #include "template.hpp" - -// #include "token.hpp" - -// #include "utils.hpp" - - -namespace inja { - -/*! - * \brief Class for parsing an inja Template. - */ -class Parser { - const ParserConfig& config; - - Lexer lexer; - TemplateStorage& template_storage; - const FunctionStorage& function_storage; - - Token tok, peek_tok; - bool have_peek_tok {false}; - - size_t current_paren_level {0}; - size_t current_bracket_level {0}; - size_t current_brace_level {0}; - - std::string_view literal_start; - - BlockNode* current_block {nullptr}; - ExpressionListNode* current_expression_list {nullptr}; - std::stack> function_stack; - std::vector> arguments; - - std::stack> operator_stack; - std::stack if_statement_stack; - std::stack for_statement_stack; - std::stack block_statement_stack; - - inline void throw_parser_error(const std::string& message) const { - INJA_THROW(ParserError(message, lexer.current_position())); - } - - inline void get_next_token() { - if (have_peek_tok) { - tok = peek_tok; - have_peek_tok = false; - } else { - tok = lexer.scan(); - } - } - - inline void get_peek_token() { - if (!have_peek_tok) { - peek_tok = lexer.scan(); - have_peek_tok = true; - } - } - - inline void add_literal(const char* content_ptr) { - std::string_view data_text(literal_start.data(), tok.text.data() - literal_start.data() + tok.text.size()); - arguments.emplace_back(std::make_shared(data_text, data_text.data() - content_ptr)); - } - - inline void add_operator() { - auto function = operator_stack.top(); - operator_stack.pop(); - - for (int i = 0; i < function->number_args; ++i) { - function->arguments.insert(function->arguments.begin(), arguments.back()); - arguments.pop_back(); - } - arguments.emplace_back(function); - } - - void add_to_template_storage(std::string_view path, std::string& template_name) { - if (template_storage.find(template_name) != template_storage.end()) { - return; - } - - std::string original_path = static_cast(path); - std::string original_name = template_name; - - if (config.search_included_templates_in_files) { - // Build the relative path - template_name = original_path + original_name; - if (template_name.compare(0, 2, "./") == 0) { - template_name.erase(0, 2); - } - - if (template_storage.find(template_name) == template_storage.end()) { - // Load file - std::ifstream file; - file.open(template_name); - if (!file.fail()) { - std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - - auto include_template = Template(text); - template_storage.emplace(template_name, include_template); - parse_into_template(template_storage[template_name], template_name); - return; - } else if (!config.include_callback) { - INJA_THROW(FileError("failed accessing file at '" + template_name + "'")); - } - } - } - - // Try include callback - if (config.include_callback) { - auto include_template = config.include_callback(original_path, original_name); - template_storage.emplace(template_name, include_template); - } - } - - std::string parse_filename(const Token& tok) const { - if (tok.kind != Token::Kind::String) { - throw_parser_error("expected string, got '" + tok.describe() + "'"); - } - - if (tok.text.length() < 2) { - throw_parser_error("expected filename, got '" + static_cast(tok.text) + "'"); - } - - // Remove first and last character "" - return std::string {tok.text.substr(1, tok.text.length() - 2)}; - } - - bool parse_expression(Template& tmpl, Token::Kind closing) { - while (tok.kind != closing && tok.kind != Token::Kind::Eof) { - // Literals - switch (tok.kind) { - case Token::Kind::String: { - if (current_brace_level == 0 && current_bracket_level == 0) { - literal_start = tok.text; - add_literal(tmpl.content.c_str()); - } - } break; - case Token::Kind::Number: { - if (current_brace_level == 0 && current_bracket_level == 0) { - literal_start = tok.text; - add_literal(tmpl.content.c_str()); - } - } break; - case Token::Kind::LeftBracket: { - if (current_brace_level == 0 && current_bracket_level == 0) { - literal_start = tok.text; - } - current_bracket_level += 1; - } break; - case Token::Kind::LeftBrace: { - if (current_brace_level == 0 && current_bracket_level == 0) { - literal_start = tok.text; - } - current_brace_level += 1; - } break; - case Token::Kind::RightBracket: { - if (current_bracket_level == 0) { - throw_parser_error("unexpected ']'"); - } - - current_bracket_level -= 1; - if (current_brace_level == 0 && current_bracket_level == 0) { - add_literal(tmpl.content.c_str()); - } - } break; - case Token::Kind::RightBrace: { - if (current_brace_level == 0) { - throw_parser_error("unexpected '}'"); - } - - current_brace_level -= 1; - if (current_brace_level == 0 && current_bracket_level == 0) { - add_literal(tmpl.content.c_str()); - } - } break; - case Token::Kind::Id: { - get_peek_token(); - - // Data Literal - if (tok.text == static_cast("true") || tok.text == static_cast("false") || - tok.text == static_cast("null")) { - if (current_brace_level == 0 && current_bracket_level == 0) { - literal_start = tok.text; - add_literal(tmpl.content.c_str()); - } - - // Operator - } else if (tok.text == "and" || tok.text == "or" || tok.text == "in" || tok.text == "not") { - goto parse_operator; - - // Functions - } else if (peek_tok.kind == Token::Kind::LeftParen) { - operator_stack.emplace(std::make_shared(static_cast(tok.text), tok.text.data() - tmpl.content.c_str())); - function_stack.emplace(operator_stack.top().get(), current_paren_level); - - // Variables - } else { - arguments.emplace_back(std::make_shared(static_cast(tok.text), tok.text.data() - tmpl.content.c_str())); - } - - // Operators - } break; - case Token::Kind::Equal: - case Token::Kind::NotEqual: - case Token::Kind::GreaterThan: - case Token::Kind::GreaterEqual: - case Token::Kind::LessThan: - case Token::Kind::LessEqual: - case Token::Kind::Plus: - case Token::Kind::Minus: - case Token::Kind::Times: - case Token::Kind::Slash: - case Token::Kind::Power: - case Token::Kind::Percent: - case Token::Kind::Dot: { - - parse_operator: - FunctionStorage::Operation operation; - switch (tok.kind) { - case Token::Kind::Id: { - if (tok.text == "and") { - operation = FunctionStorage::Operation::And; - } else if (tok.text == "or") { - operation = FunctionStorage::Operation::Or; - } else if (tok.text == "in") { - operation = FunctionStorage::Operation::In; - } else if (tok.text == "not") { - operation = FunctionStorage::Operation::Not; - } else { - throw_parser_error("unknown operator in parser."); - } - } break; - case Token::Kind::Equal: { - operation = FunctionStorage::Operation::Equal; - } break; - case Token::Kind::NotEqual: { - operation = FunctionStorage::Operation::NotEqual; - } break; - case Token::Kind::GreaterThan: { - operation = FunctionStorage::Operation::Greater; - } break; - case Token::Kind::GreaterEqual: { - operation = FunctionStorage::Operation::GreaterEqual; - } break; - case Token::Kind::LessThan: { - operation = FunctionStorage::Operation::Less; - } break; - case Token::Kind::LessEqual: { - operation = FunctionStorage::Operation::LessEqual; - } break; - case Token::Kind::Plus: { - operation = FunctionStorage::Operation::Add; - } break; - case Token::Kind::Minus: { - operation = FunctionStorage::Operation::Subtract; - } break; - case Token::Kind::Times: { - operation = FunctionStorage::Operation::Multiplication; - } break; - case Token::Kind::Slash: { - operation = FunctionStorage::Operation::Division; - } break; - case Token::Kind::Power: { - operation = FunctionStorage::Operation::Power; - } break; - case Token::Kind::Percent: { - operation = FunctionStorage::Operation::Modulo; - } break; - case Token::Kind::Dot: { - operation = FunctionStorage::Operation::AtId; - } break; - default: { - throw_parser_error("unknown operator in parser."); - } - } - auto function_node = std::make_shared(operation, tok.text.data() - tmpl.content.c_str()); - - while (!operator_stack.empty() && - ((operator_stack.top()->precedence > function_node->precedence) || - (operator_stack.top()->precedence == function_node->precedence && function_node->associativity == FunctionNode::Associativity::Left)) && - (operator_stack.top()->operation != FunctionStorage::Operation::ParenLeft)) { - add_operator(); - } - - operator_stack.emplace(function_node); - } break; - case Token::Kind::Comma: { - if (current_brace_level == 0 && current_bracket_level == 0) { - if (function_stack.empty()) { - throw_parser_error("unexpected ','"); - } - - function_stack.top().first->number_args += 1; - } - } break; - case Token::Kind::Colon: { - if (current_brace_level == 0 && current_bracket_level == 0) { - throw_parser_error("unexpected ':'"); - } - } break; - case Token::Kind::LeftParen: { - current_paren_level += 1; - operator_stack.emplace(std::make_shared(FunctionStorage::Operation::ParenLeft, tok.text.data() - tmpl.content.c_str())); - - get_peek_token(); - if (peek_tok.kind == Token::Kind::RightParen) { - if (!function_stack.empty() && function_stack.top().second == current_paren_level - 1) { - function_stack.top().first->number_args = 0; - } - } - } break; - case Token::Kind::RightParen: { - current_paren_level -= 1; - while (!operator_stack.empty() && operator_stack.top()->operation != FunctionStorage::Operation::ParenLeft) { - add_operator(); - } - - if (!operator_stack.empty() && operator_stack.top()->operation == FunctionStorage::Operation::ParenLeft) { - operator_stack.pop(); - } - - if (!function_stack.empty() && function_stack.top().second == current_paren_level) { - auto func = function_stack.top().first; - auto function_data = function_storage.find_function(func->name, func->number_args); - if (function_data.operation == FunctionStorage::Operation::None) { - throw_parser_error("unknown function " + func->name); - } - func->operation = function_data.operation; - if (function_data.operation == FunctionStorage::Operation::Callback) { - func->callback = function_data.callback; - } - - if (operator_stack.empty()) { - throw_parser_error("internal error at function " + func->name); - } - - add_operator(); - function_stack.pop(); - } - } - default: - break; - } - - get_next_token(); - } - - while (!operator_stack.empty()) { - add_operator(); - } - - if (arguments.size() == 1) { - current_expression_list->root = arguments[0]; - arguments = {}; - } else if (arguments.size() > 1) { - throw_parser_error("malformed expression"); - } - - return true; - } - - bool parse_statement(Template& tmpl, Token::Kind closing, std::string_view path) { - if (tok.kind != Token::Kind::Id) { - return false; - } - - if (tok.text == static_cast("if")) { - get_next_token(); - - auto if_statement_node = std::make_shared(current_block, tok.text.data() - tmpl.content.c_str()); - current_block->nodes.emplace_back(if_statement_node); - if_statement_stack.emplace(if_statement_node.get()); - current_block = &if_statement_node->true_statement; - current_expression_list = &if_statement_node->condition; - - if (!parse_expression(tmpl, closing)) { - return false; - } - } else if (tok.text == static_cast("else")) { - if (if_statement_stack.empty()) { - throw_parser_error("else without matching if"); - } - auto& if_statement_data = if_statement_stack.top(); - get_next_token(); - - if_statement_data->has_false_statement = true; - current_block = &if_statement_data->false_statement; - - // Chained else if - if (tok.kind == Token::Kind::Id && tok.text == static_cast("if")) { - get_next_token(); - - auto if_statement_node = std::make_shared(true, current_block, tok.text.data() - tmpl.content.c_str()); - current_block->nodes.emplace_back(if_statement_node); - if_statement_stack.emplace(if_statement_node.get()); - current_block = &if_statement_node->true_statement; - current_expression_list = &if_statement_node->condition; - - if (!parse_expression(tmpl, closing)) { - return false; - } - } - } else if (tok.text == static_cast("endif")) { - if (if_statement_stack.empty()) { - throw_parser_error("endif without matching if"); - } - - // Nested if statements - while (if_statement_stack.top()->is_nested) { - if_statement_stack.pop(); - } - - auto& if_statement_data = if_statement_stack.top(); - get_next_token(); - - current_block = if_statement_data->parent; - if_statement_stack.pop(); - } else if (tok.text == static_cast("block")) { - get_next_token(); - - if (tok.kind != Token::Kind::Id) { - throw_parser_error("expected block name, got '" + tok.describe() + "'"); - } - - const std::string block_name = static_cast(tok.text); - - auto block_statement_node = std::make_shared(current_block, block_name, tok.text.data() - tmpl.content.c_str()); - current_block->nodes.emplace_back(block_statement_node); - block_statement_stack.emplace(block_statement_node.get()); - current_block = &block_statement_node->block; - auto success = tmpl.block_storage.emplace(block_name, block_statement_node); - if (!success.second) { - throw_parser_error("block with the name '" + block_name + "' does already exist"); - } - - get_next_token(); - } else if (tok.text == static_cast("endblock")) { - if (block_statement_stack.empty()) { - throw_parser_error("endblock without matching block"); - } - - auto& block_statement_data = block_statement_stack.top(); - get_next_token(); - - current_block = block_statement_data->parent; - block_statement_stack.pop(); - } else if (tok.text == static_cast("for")) { - get_next_token(); - - // options: for a in arr; for a, b in obj - if (tok.kind != Token::Kind::Id) { - throw_parser_error("expected id, got '" + tok.describe() + "'"); - } - - Token value_token = tok; - get_next_token(); - - // Object type - std::shared_ptr for_statement_node; - if (tok.kind == Token::Kind::Comma) { - get_next_token(); - if (tok.kind != Token::Kind::Id) { - throw_parser_error("expected id, got '" + tok.describe() + "'"); - } - - Token key_token = std::move(value_token); - value_token = tok; - get_next_token(); - - for_statement_node = std::make_shared(static_cast(key_token.text), static_cast(value_token.text), - current_block, tok.text.data() - tmpl.content.c_str()); - - // Array type - } else { - for_statement_node = - std::make_shared(static_cast(value_token.text), current_block, tok.text.data() - tmpl.content.c_str()); - } - - current_block->nodes.emplace_back(for_statement_node); - for_statement_stack.emplace(for_statement_node.get()); - current_block = &for_statement_node->body; - current_expression_list = &for_statement_node->condition; - - if (tok.kind != Token::Kind::Id || tok.text != static_cast("in")) { - throw_parser_error("expected 'in', got '" + tok.describe() + "'"); - } - get_next_token(); - - if (!parse_expression(tmpl, closing)) { - return false; - } - } else if (tok.text == static_cast("endfor")) { - if (for_statement_stack.empty()) { - throw_parser_error("endfor without matching for"); - } - - auto& for_statement_data = for_statement_stack.top(); - get_next_token(); - - current_block = for_statement_data->parent; - for_statement_stack.pop(); - } else if (tok.text == static_cast("include")) { - get_next_token(); - - std::string template_name = parse_filename(tok); - add_to_template_storage(path, template_name); - - current_block->nodes.emplace_back(std::make_shared(template_name, tok.text.data() - tmpl.content.c_str())); - - get_next_token(); - } else if (tok.text == static_cast("extends")) { - get_next_token(); - - std::string template_name = parse_filename(tok); - add_to_template_storage(path, template_name); - - current_block->nodes.emplace_back(std::make_shared(template_name, tok.text.data() - tmpl.content.c_str())); - - get_next_token(); - } else if (tok.text == static_cast("set")) { - get_next_token(); - - if (tok.kind != Token::Kind::Id) { - throw_parser_error("expected variable name, got '" + tok.describe() + "'"); - } - - std::string key = static_cast(tok.text); - get_next_token(); - - auto set_statement_node = std::make_shared(key, tok.text.data() - tmpl.content.c_str()); - current_block->nodes.emplace_back(set_statement_node); - current_expression_list = &set_statement_node->expression; - - if (tok.text != static_cast("=")) { - throw_parser_error("expected '=', got '" + tok.describe() + "'"); - } - get_next_token(); - - if (!parse_expression(tmpl, closing)) { - return false; - } - } else { - return false; - } - return true; - } - - void parse_into(Template& tmpl, std::string_view path) { - lexer.start(tmpl.content); - current_block = &tmpl.root; - - for (;;) { - get_next_token(); - switch (tok.kind) { - case Token::Kind::Eof: { - if (!if_statement_stack.empty()) { - throw_parser_error("unmatched if"); - } - if (!for_statement_stack.empty()) { - throw_parser_error("unmatched for"); - } - } - return; - case Token::Kind::Text: { - current_block->nodes.emplace_back(std::make_shared(tok.text.data() - tmpl.content.c_str(), tok.text.size())); - } break; - case Token::Kind::StatementOpen: { - get_next_token(); - if (!parse_statement(tmpl, Token::Kind::StatementClose, path)) { - throw_parser_error("expected statement, got '" + tok.describe() + "'"); - } - if (tok.kind != Token::Kind::StatementClose) { - throw_parser_error("expected statement close, got '" + tok.describe() + "'"); - } - } break; - case Token::Kind::LineStatementOpen: { - get_next_token(); - if (!parse_statement(tmpl, Token::Kind::LineStatementClose, path)) { - throw_parser_error("expected statement, got '" + tok.describe() + "'"); - } - if (tok.kind != Token::Kind::LineStatementClose && tok.kind != Token::Kind::Eof) { - throw_parser_error("expected line statement close, got '" + tok.describe() + "'"); - } - } break; - case Token::Kind::ExpressionOpen: { - get_next_token(); - - auto expression_list_node = std::make_shared(tok.text.data() - tmpl.content.c_str()); - current_block->nodes.emplace_back(expression_list_node); - current_expression_list = expression_list_node.get(); - - if (!parse_expression(tmpl, Token::Kind::ExpressionClose)) { - throw_parser_error("expected expression, got '" + tok.describe() + "'"); - } - - if (tok.kind != Token::Kind::ExpressionClose) { - throw_parser_error("expected expression close, got '" + tok.describe() + "'"); - } - } break; - case Token::Kind::CommentOpen: { - get_next_token(); - if (tok.kind != Token::Kind::CommentClose) { - throw_parser_error("expected comment close, got '" + tok.describe() + "'"); - } - } break; - default: { - throw_parser_error("unexpected token '" + tok.describe() + "'"); - } break; - } - } - } - -public: - explicit Parser(const ParserConfig& parser_config, const LexerConfig& lexer_config, TemplateStorage& template_storage, - const FunctionStorage& function_storage) - : config(parser_config), lexer(lexer_config), template_storage(template_storage), function_storage(function_storage) {} - - Template parse(std::string_view input, std::string_view path) { - auto result = Template(static_cast(input)); - parse_into(result, path); - return result; - } - - Template parse(std::string_view input) { - return parse(input, "./"); - } - - void parse_into_template(Template& tmpl, std::string_view filename) { - std::string_view path = filename.substr(0, filename.find_last_of("/\\") + 1); - - // StringRef path = sys::path::parent_path(filename); - auto sub_parser = Parser(config, lexer.get_config(), template_storage, function_storage); - sub_parser.parse_into(tmpl, path); - } - - std::string load_file(const std::string& filename) { - std::ifstream file; - file.open(filename); - if (file.fail()) { - INJA_THROW(FileError("failed accessing file at '" + filename + "'")); - } - std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - return text; - } -}; - -} // namespace inja - -#endif // INCLUDE_INJA_PARSER_HPP_ - -// #include "renderer.hpp" -#ifndef INCLUDE_INJA_RENDERER_HPP_ -#define INCLUDE_INJA_RENDERER_HPP_ - -#include -#include -#include -#include -#include - -// #include "config.hpp" - -// #include "exceptions.hpp" - -// #include "node.hpp" - -// #include "template.hpp" - -// #include "utils.hpp" - - -namespace inja { - -/*! - * \brief Class for rendering a Template with data. - */ -class Renderer : public NodeVisitor { - using Op = FunctionStorage::Operation; - - const RenderConfig config; - const TemplateStorage& template_storage; - const FunctionStorage& function_storage; - - const Template* current_template; - size_t current_level {0}; - std::vector template_stack; - std::vector block_statement_stack; - - const json* data_input; - std::ostream* output_stream; - - json additional_data; - json* current_loop_data = &additional_data["loop"]; - - std::vector> data_tmp_stack; - std::stack data_eval_stack; - std::stack not_found_stack; - - bool break_rendering {false}; - - static bool truthy(const json* data) { - if (data->is_boolean()) { - return data->get(); - } else if (data->is_number()) { - return (*data != 0); - } else if (data->is_null()) { - return false; - } - return !data->empty(); - } - - void print_data(const std::shared_ptr value) { - if (value->is_string()) { - *output_stream << value->get_ref(); - } else if (value->is_number_integer()) { - *output_stream << value->get(); - } else if (value->is_null()) { - } else { - *output_stream << value->dump(); - } - } - - const std::shared_ptr eval_expression_list(const ExpressionListNode& expression_list) { - if (!expression_list.root) { - throw_renderer_error("empty expression", expression_list); - } - - expression_list.root->accept(*this); - - if (data_eval_stack.empty()) { - throw_renderer_error("empty expression", expression_list); - } else if (data_eval_stack.size() != 1) { - throw_renderer_error("malformed expression", expression_list); - } - - const auto result = data_eval_stack.top(); - data_eval_stack.pop(); - - if (!result) { - if (not_found_stack.empty()) { - throw_renderer_error("expression could not be evaluated", expression_list); - } - - auto node = not_found_stack.top(); - not_found_stack.pop(); - - throw_renderer_error("variable '" + static_cast(node->name) + "' not found", *node); - } - return std::make_shared(*result); - } - - void throw_renderer_error(const std::string& message, const AstNode& node) { - SourceLocation loc = get_source_location(current_template->content, node.pos); - INJA_THROW(RenderError(message, loc)); - } - - void make_result(const json&& result) { - auto result_ptr = std::make_shared(result); - data_tmp_stack.push_back(result_ptr); - data_eval_stack.push(result_ptr.get()); - } - - template std::array get_arguments(const FunctionNode& node) { - if (node.arguments.size() < N_start + N) { - throw_renderer_error("function needs " + std::to_string(N_start + N) + " variables, but has only found " + std::to_string(node.arguments.size()), node); - } - - for (size_t i = N_start; i < N_start + N; i += 1) { - node.arguments[i]->accept(*this); - } - - if (data_eval_stack.size() < N) { - throw_renderer_error("function needs " + std::to_string(N) + " variables, but has only found " + std::to_string(data_eval_stack.size()), node); - } - - std::array result; - for (size_t i = 0; i < N; i += 1) { - result[N - i - 1] = data_eval_stack.top(); - data_eval_stack.pop(); - - if (!result[N - i - 1]) { - const auto data_node = not_found_stack.top(); - not_found_stack.pop(); - - if (throw_not_found) { - throw_renderer_error("variable '" + static_cast(data_node->name) + "' not found", *data_node); - } - } - } - return result; - } - - template Arguments get_argument_vector(const FunctionNode& node) { - const size_t N = node.arguments.size(); - for (auto a : node.arguments) { - a->accept(*this); - } - - if (data_eval_stack.size() < N) { - throw_renderer_error("function needs " + std::to_string(N) + " variables, but has only found " + std::to_string(data_eval_stack.size()), node); - } - - Arguments result {N}; - for (size_t i = 0; i < N; i += 1) { - result[N - i - 1] = data_eval_stack.top(); - data_eval_stack.pop(); - - if (!result[N - i - 1]) { - const auto data_node = not_found_stack.top(); - not_found_stack.pop(); - - if (throw_not_found) { - throw_renderer_error("variable '" + static_cast(data_node->name) + "' not found", *data_node); - } - } - } - return result; - } - - void visit(const BlockNode& node) { - for (auto& n : node.nodes) { - n->accept(*this); - - if (break_rendering) { - break; - } - } - } - - void visit(const TextNode& node) { - output_stream->write(current_template->content.c_str() + node.pos, node.length); - } - - void visit(const ExpressionNode&) {} - - void visit(const LiteralNode& node) { - data_eval_stack.push(&node.value); - } - - void visit(const DataNode& node) { - if (additional_data.contains(node.ptr)) { - data_eval_stack.push(&(additional_data[node.ptr])); - } else if (data_input->contains(node.ptr)) { - data_eval_stack.push(&(*data_input)[node.ptr]); - } else { - // Try to evaluate as a no-argument callback - const auto function_data = function_storage.find_function(node.name, 0); - if (function_data.operation == FunctionStorage::Operation::Callback) { - Arguments empty_args {}; - const auto value = std::make_shared(function_data.callback(empty_args)); - data_tmp_stack.push_back(value); - data_eval_stack.push(value.get()); - } else { - data_eval_stack.push(nullptr); - not_found_stack.emplace(&node); - } - } - } - - void visit(const FunctionNode& node) { - switch (node.operation) { - case Op::Not: { - const auto args = get_arguments<1>(node); - make_result(!truthy(args[0])); - } break; - case Op::And: { - make_result(truthy(get_arguments<1, 0>(node)[0]) && truthy(get_arguments<1, 1>(node)[0])); - } break; - case Op::Or: { - make_result(truthy(get_arguments<1, 0>(node)[0]) || truthy(get_arguments<1, 1>(node)[0])); - } break; - case Op::In: { - const auto args = get_arguments<2>(node); - make_result(std::find(args[1]->begin(), args[1]->end(), *args[0]) != args[1]->end()); - } break; - case Op::Equal: { - const auto args = get_arguments<2>(node); - make_result(*args[0] == *args[1]); - } break; - case Op::NotEqual: { - const auto args = get_arguments<2>(node); - make_result(*args[0] != *args[1]); - } break; - case Op::Greater: { - const auto args = get_arguments<2>(node); - make_result(*args[0] > *args[1]); - } break; - case Op::GreaterEqual: { - const auto args = get_arguments<2>(node); - make_result(*args[0] >= *args[1]); - } break; - case Op::Less: { - const auto args = get_arguments<2>(node); - make_result(*args[0] < *args[1]); - } break; - case Op::LessEqual: { - const auto args = get_arguments<2>(node); - make_result(*args[0] <= *args[1]); - } break; - case Op::Add: { - const auto args = get_arguments<2>(node); - if (args[0]->is_string() && args[1]->is_string()) { - make_result(args[0]->get_ref() + args[1]->get_ref()); - } else if (args[0]->is_number_integer() && args[1]->is_number_integer()) { - make_result(args[0]->get() + args[1]->get()); - } else { - make_result(args[0]->get() + args[1]->get()); - } - } break; - case Op::Subtract: { - const auto args = get_arguments<2>(node); - if (args[0]->is_number_integer() && args[1]->is_number_integer()) { - make_result(args[0]->get() - args[1]->get()); - } else { - make_result(args[0]->get() - args[1]->get()); - } - } break; - case Op::Multiplication: { - const auto args = get_arguments<2>(node); - if (args[0]->is_number_integer() && args[1]->is_number_integer()) { - make_result(args[0]->get() * args[1]->get()); - } else { - make_result(args[0]->get() * args[1]->get()); - } - } break; - case Op::Division: { - const auto args = get_arguments<2>(node); - if (args[1]->get() == 0) { - throw_renderer_error("division by zero", node); - } - make_result(args[0]->get() / args[1]->get()); - } break; - case Op::Power: { - const auto args = get_arguments<2>(node); - if (args[0]->is_number_integer() && args[1]->get() >= 0) { - int result = static_cast(std::pow(args[0]->get(), args[1]->get())); - make_result(result); - } else { - double result = std::pow(args[0]->get(), args[1]->get()); - make_result(result); - } - } break; - case Op::Modulo: { - const auto args = get_arguments<2>(node); - make_result(args[0]->get() % args[1]->get()); - } break; - case Op::AtId: { - const auto container = get_arguments<1, 0, false>(node)[0]; - node.arguments[1]->accept(*this); - if (not_found_stack.empty()) { - throw_renderer_error("could not find element with given name", node); - } - const auto id_node = not_found_stack.top(); - not_found_stack.pop(); - data_eval_stack.pop(); - data_eval_stack.push(&container->at(id_node->name)); - } break; - case Op::At: { - const auto args = get_arguments<2>(node); - if (args[0]->is_object()) { - data_eval_stack.push(&args[0]->at(args[1]->get())); - } else { - data_eval_stack.push(&args[0]->at(args[1]->get())); - } - } break; - case Op::Default: { - const auto test_arg = get_arguments<1, 0, false>(node)[0]; - data_eval_stack.push(test_arg ? test_arg : get_arguments<1, 1>(node)[0]); - } break; - case Op::DivisibleBy: { - const auto args = get_arguments<2>(node); - const int divisor = args[1]->get(); - make_result((divisor != 0) && (args[0]->get() % divisor == 0)); - } break; - case Op::Even: { - make_result(get_arguments<1>(node)[0]->get() % 2 == 0); - } break; - case Op::Exists: { - auto&& name = get_arguments<1>(node)[0]->get_ref(); - make_result(data_input->contains(json::json_pointer(DataNode::convert_dot_to_ptr(name)))); - } break; - case Op::ExistsInObject: { - const auto args = get_arguments<2>(node); - auto&& name = args[1]->get_ref(); - make_result(args[0]->find(name) != args[0]->end()); - } break; - case Op::First: { - const auto result = &get_arguments<1>(node)[0]->front(); - data_eval_stack.push(result); - } break; - case Op::Float: { - make_result(std::stod(get_arguments<1>(node)[0]->get_ref())); - } break; - case Op::Int: { - make_result(std::stoi(get_arguments<1>(node)[0]->get_ref())); - } break; - case Op::Last: { - const auto result = &get_arguments<1>(node)[0]->back(); - data_eval_stack.push(result); - } break; - case Op::Length: { - const auto val = get_arguments<1>(node)[0]; - if (val->is_string()) { - make_result(val->get_ref().length()); - } else { - make_result(val->size()); - } - } break; - case Op::Lower: { - std::string result = get_arguments<1>(node)[0]->get(); - std::transform(result.begin(), result.end(), result.begin(), ::tolower); - make_result(std::move(result)); - } break; - case Op::Max: { - const auto args = get_arguments<1>(node); - const auto result = std::max_element(args[0]->begin(), args[0]->end()); - data_eval_stack.push(&(*result)); - } break; - case Op::Min: { - const auto args = get_arguments<1>(node); - const auto result = std::min_element(args[0]->begin(), args[0]->end()); - data_eval_stack.push(&(*result)); - } break; - case Op::Odd: { - make_result(get_arguments<1>(node)[0]->get() % 2 != 0); - } break; - case Op::Range: { - std::vector result(get_arguments<1>(node)[0]->get()); - std::iota(result.begin(), result.end(), 0); - make_result(std::move(result)); - } break; - case Op::Round: { - const auto args = get_arguments<2>(node); - const int precision = args[1]->get(); - const double result = std::round(args[0]->get() * std::pow(10.0, precision)) / std::pow(10.0, precision); - if (precision == 0) { - make_result(int(result)); - } else { - make_result(result); - } - } break; - case Op::Sort: { - auto result_ptr = std::make_shared(get_arguments<1>(node)[0]->get>()); - std::sort(result_ptr->begin(), result_ptr->end()); - data_tmp_stack.push_back(result_ptr); - data_eval_stack.push(result_ptr.get()); - } break; - case Op::Upper: { - std::string result = get_arguments<1>(node)[0]->get(); - std::transform(result.begin(), result.end(), result.begin(), ::toupper); - make_result(std::move(result)); - } break; - case Op::IsBoolean: { - make_result(get_arguments<1>(node)[0]->is_boolean()); - } break; - case Op::IsNumber: { - make_result(get_arguments<1>(node)[0]->is_number()); - } break; - case Op::IsInteger: { - make_result(get_arguments<1>(node)[0]->is_number_integer()); - } break; - case Op::IsFloat: { - make_result(get_arguments<1>(node)[0]->is_number_float()); - } break; - case Op::IsObject: { - make_result(get_arguments<1>(node)[0]->is_object()); - } break; - case Op::IsArray: { - make_result(get_arguments<1>(node)[0]->is_array()); - } break; - case Op::IsString: { - make_result(get_arguments<1>(node)[0]->is_string()); - } break; - case Op::Callback: { - auto args = get_argument_vector(node); - make_result(node.callback(args)); - } break; - case Op::Super: { - const auto args = get_argument_vector(node); - const size_t old_level = current_level; - const size_t level_diff = (args.size() == 1) ? args[0]->get() : 1; - const size_t level = current_level + level_diff; - - if (block_statement_stack.empty()) { - throw_renderer_error("super() call is not within a block", node); - } - - if (level < 1 || level > template_stack.size() - 1) { - throw_renderer_error("level of super() call does not match parent templates (between 1 and " + std::to_string(template_stack.size() - 1) + ")", node); - } - - const auto current_block_statement = block_statement_stack.back(); - const Template* new_template = template_stack.at(level); - const Template* old_template = current_template; - const auto block_it = new_template->block_storage.find(current_block_statement->name); - if (block_it != new_template->block_storage.end()) { - current_template = new_template; - current_level = level; - block_it->second->block.accept(*this); - current_level = old_level; - current_template = old_template; - } else { - throw_renderer_error("could not find block with name '" + current_block_statement->name + "'", node); - } - make_result(nullptr); - } break; - case Op::Join: { - const auto args = get_arguments<2>(node); - const auto separator = args[1]->get(); - std::ostringstream os; - std::string sep; - for (const auto& value : *args[0]) { - os << sep; - if (value.is_string()) { - os << value.get(); // otherwise the value is surrounded with "" - } else { - os << value.dump(); - } - sep = separator; - } - make_result(os.str()); - } break; - case Op::ParenLeft: - case Op::ParenRight: - case Op::None: - break; - } - } - - void visit(const ExpressionListNode& node) { - print_data(eval_expression_list(node)); - } - - void visit(const StatementNode&) {} - - void visit(const ForStatementNode&) {} - - void visit(const ForArrayStatementNode& node) { - const auto result = eval_expression_list(node.condition); - if (!result->is_array()) { - throw_renderer_error("object must be an array", node); - } - - if (!current_loop_data->empty()) { - auto tmp = *current_loop_data; // Because of clang-3 - (*current_loop_data)["parent"] = std::move(tmp); - } - - size_t index = 0; - (*current_loop_data)["is_first"] = true; - (*current_loop_data)["is_last"] = (result->size() <= 1); - for (auto it = result->begin(); it != result->end(); ++it) { - additional_data[static_cast(node.value)] = *it; - - (*current_loop_data)["index"] = index; - (*current_loop_data)["index1"] = index + 1; - if (index == 1) { - (*current_loop_data)["is_first"] = false; - } - if (index == result->size() - 1) { - (*current_loop_data)["is_last"] = true; - } - - node.body.accept(*this); - ++index; - } - - additional_data[static_cast(node.value)].clear(); - if (!(*current_loop_data)["parent"].empty()) { - const auto tmp = (*current_loop_data)["parent"]; - *current_loop_data = std::move(tmp); - } else { - current_loop_data = &additional_data["loop"]; - } - } - - void visit(const ForObjectStatementNode& node) { - const auto result = eval_expression_list(node.condition); - if (!result->is_object()) { - throw_renderer_error("object must be an object", node); - } - - if (!current_loop_data->empty()) { - (*current_loop_data)["parent"] = std::move(*current_loop_data); - } - - size_t index = 0; - (*current_loop_data)["is_first"] = true; - (*current_loop_data)["is_last"] = (result->size() <= 1); - for (auto it = result->begin(); it != result->end(); ++it) { - additional_data[static_cast(node.key)] = it.key(); - additional_data[static_cast(node.value)] = it.value(); - - (*current_loop_data)["index"] = index; - (*current_loop_data)["index1"] = index + 1; - if (index == 1) { - (*current_loop_data)["is_first"] = false; - } - if (index == result->size() - 1) { - (*current_loop_data)["is_last"] = true; - } - - node.body.accept(*this); - ++index; - } - - additional_data[static_cast(node.key)].clear(); - additional_data[static_cast(node.value)].clear(); - if (!(*current_loop_data)["parent"].empty()) { - *current_loop_data = std::move((*current_loop_data)["parent"]); - } else { - current_loop_data = &additional_data["loop"]; - } - } - - void visit(const IfStatementNode& node) { - const auto result = eval_expression_list(node.condition); - if (truthy(result.get())) { - node.true_statement.accept(*this); - } else if (node.has_false_statement) { - node.false_statement.accept(*this); - } - } - - void visit(const IncludeStatementNode& node) { - auto sub_renderer = Renderer(config, template_storage, function_storage); - const auto included_template_it = template_storage.find(node.file); - if (included_template_it != template_storage.end()) { - sub_renderer.render_to(*output_stream, included_template_it->second, *data_input, &additional_data); - } else if (config.throw_at_missing_includes) { - throw_renderer_error("include '" + node.file + "' not found", node); - } - } - - void visit(const ExtendsStatementNode& node) { - const auto included_template_it = template_storage.find(node.file); - if (included_template_it != template_storage.end()) { - const Template* parent_template = &included_template_it->second; - render_to(*output_stream, *parent_template, *data_input, &additional_data); - break_rendering = true; - } else if (config.throw_at_missing_includes) { - throw_renderer_error("extends '" + node.file + "' not found", node); - } - } - - void visit(const BlockStatementNode& node) { - const size_t old_level = current_level; - current_level = 0; - current_template = template_stack.front(); - const auto block_it = current_template->block_storage.find(node.name); - if (block_it != current_template->block_storage.end()) { - block_statement_stack.emplace_back(&node); - block_it->second->block.accept(*this); - block_statement_stack.pop_back(); - } - current_level = old_level; - current_template = template_stack.back(); - } - - void visit(const SetStatementNode& node) { - std::string ptr = node.key; - replace_substring(ptr, ".", "/"); - ptr = "/" + ptr; - additional_data[json::json_pointer(ptr)] = *eval_expression_list(node.expression); - } - -public: - Renderer(const RenderConfig& config, const TemplateStorage& template_storage, const FunctionStorage& function_storage) - : config(config), template_storage(template_storage), function_storage(function_storage) {} - - void render_to(std::ostream& os, const Template& tmpl, const json& data, json* loop_data = nullptr) { - output_stream = &os; - current_template = &tmpl; - data_input = &data; - if (loop_data) { - additional_data = *loop_data; - current_loop_data = &additional_data["loop"]; - } - - template_stack.emplace_back(current_template); - current_template->root.accept(*this); - - data_tmp_stack.clear(); - } -}; - -} // namespace inja - -#endif // INCLUDE_INJA_RENDERER_HPP_ - -// #include "template.hpp" - -// #include "utils.hpp" - - -namespace inja { - -/*! - * \brief Class for changing the configuration. - */ -class Environment { - std::string input_path; - std::string output_path; - - LexerConfig lexer_config; - ParserConfig parser_config; - RenderConfig render_config; - - FunctionStorage function_storage; - TemplateStorage template_storage; - -public: - Environment(): Environment("") {} - - explicit Environment(const std::string& global_path): input_path(global_path), output_path(global_path) {} - - Environment(const std::string& input_path, const std::string& output_path): input_path(input_path), output_path(output_path) {} - - /// Sets the opener and closer for template statements - void set_statement(const std::string& open, const std::string& close) { - lexer_config.statement_open = open; - lexer_config.statement_open_no_lstrip = open + "+"; - lexer_config.statement_open_force_lstrip = open + "-"; - lexer_config.statement_close = close; - lexer_config.statement_close_force_rstrip = "-" + close; - lexer_config.update_open_chars(); - } - - /// Sets the opener for template line statements - void set_line_statement(const std::string& open) { - lexer_config.line_statement = open; - lexer_config.update_open_chars(); - } - - /// Sets the opener and closer for template expressions - void set_expression(const std::string& open, const std::string& close) { - lexer_config.expression_open = open; - lexer_config.expression_open_force_lstrip = open + "-"; - lexer_config.expression_close = close; - lexer_config.expression_close_force_rstrip = "-" + close; - lexer_config.update_open_chars(); - } - - /// Sets the opener and closer for template comments - void set_comment(const std::string& open, const std::string& close) { - lexer_config.comment_open = open; - lexer_config.comment_open_force_lstrip = open + "-"; - lexer_config.comment_close = close; - lexer_config.comment_close_force_rstrip = "-" + close; - lexer_config.update_open_chars(); - } - - /// Sets whether to remove the first newline after a block - void set_trim_blocks(bool trim_blocks) { - lexer_config.trim_blocks = trim_blocks; - } - - /// Sets whether to strip the spaces and tabs from the start of a line to a block - void set_lstrip_blocks(bool lstrip_blocks) { - lexer_config.lstrip_blocks = lstrip_blocks; - } - - /// Sets the element notation syntax - void set_search_included_templates_in_files(bool search_in_files) { - parser_config.search_included_templates_in_files = search_in_files; - } - - /// Sets whether a missing include will throw an error - void set_throw_at_missing_includes(bool will_throw) { - render_config.throw_at_missing_includes = will_throw; - } - - Template parse(std::string_view input) { - Parser parser(parser_config, lexer_config, template_storage, function_storage); - return parser.parse(input); - } - - Template parse_template(const std::string& filename) { - Parser parser(parser_config, lexer_config, template_storage, function_storage); - auto result = Template(parser.load_file(input_path + static_cast(filename))); - parser.parse_into_template(result, input_path + static_cast(filename)); - return result; - } - - Template parse_file(const std::string& filename) { - return parse_template(filename); - } - - std::string render(std::string_view input, const json& data) { - return render(parse(input), data); - } - - std::string render(const Template& tmpl, const json& data) { - std::stringstream os; - render_to(os, tmpl, data); - return os.str(); - } - - std::string render_file(const std::string& filename, const json& data) { - return render(parse_template(filename), data); - } - - std::string render_file_with_json_file(const std::string& filename, const std::string& filename_data) { - const json data = load_json(filename_data); - return render_file(filename, data); - } - - void write(const std::string& filename, const json& data, const std::string& filename_out) { - std::ofstream file(output_path + filename_out); - file << render_file(filename, data); - file.close(); - } - - void write(const Template& temp, const json& data, const std::string& filename_out) { - std::ofstream file(output_path + filename_out); - file << render(temp, data); - file.close(); - } - - void write_with_json_file(const std::string& filename, const std::string& filename_data, const std::string& filename_out) { - const json data = load_json(filename_data); - write(filename, data, filename_out); - } - - void write_with_json_file(const Template& temp, const std::string& filename_data, const std::string& filename_out) { - const json data = load_json(filename_data); - write(temp, data, filename_out); - } - - std::ostream& render_to(std::ostream& os, const Template& tmpl, const json& data) { - Renderer(render_config, template_storage, function_storage).render_to(os, tmpl, data); - return os; - } - - std::string load_file(const std::string& filename) { - Parser parser(parser_config, lexer_config, template_storage, function_storage); - return parser.load_file(input_path + filename); - } - - json load_json(const std::string& filename) { - std::ifstream file; - file.open(input_path + filename); - if (file.fail()) { - INJA_THROW(FileError("failed accessing file at '" + input_path + filename + "'")); - } - - return json::parse(std::istreambuf_iterator(file), std::istreambuf_iterator()); - } - - /*! - @brief Adds a variadic callback - */ - void add_callback(const std::string& name, const CallbackFunction& callback) { - add_callback(name, -1, callback); - } - - /*! - @brief Adds a variadic void callback - */ - void add_void_callback(const std::string& name, const VoidCallbackFunction& callback) { - add_void_callback(name, -1, callback); - } - - /*! - @brief Adds a callback with given number or arguments - */ - void add_callback(const std::string& name, int num_args, const CallbackFunction& callback) { - function_storage.add_callback(name, num_args, callback); - } - - /*! - @brief Adds a void callback with given number or arguments - */ - void add_void_callback(const std::string& name, int num_args, const VoidCallbackFunction& callback) { - function_storage.add_callback(name, num_args, [callback](Arguments& args) { - callback(args); - return json(); - }); - } - - /** Includes a template with a given name into the environment. - * Then, a template can be rendered in another template using the - * include "" syntax. - */ - void include_template(const std::string& name, const Template& tmpl) { - template_storage[name] = tmpl; - } - - /*! - @brief Sets a function that is called when an included file is not found - */ - void set_include_callback(const std::function& callback) { - parser_config.include_callback = callback; - } -}; - -/*! -@brief render with default settings to a string -*/ -inline std::string render(std::string_view input, const json& data) { - return Environment().render(input, data); -} - -/*! -@brief render with default settings to the given output stream -*/ -inline void render_to(std::ostream& os, std::string_view input, const json& data) { - Environment env; - env.render_to(os, env.parse(input), data); -} - -} // namespace inja - -#endif // INCLUDE_INJA_ENVIRONMENT_HPP_ - -// #include "exceptions.hpp" - -// #include "parser.hpp" - -// #include "renderer.hpp" - -// #include "template.hpp" - - -#endif // INCLUDE_INJA_INJA_HPP_ diff --git a/ext/installfiles/linux/zerotier-containerized/Dockerfile b/ext/installfiles/linux/zerotier-containerized/Dockerfile index 7758faf3..3d580566 100644 --- a/ext/installfiles/linux/zerotier-containerized/Dockerfile +++ b/ext/installfiles/linux/zerotier-containerized/Dockerfile @@ -5,13 +5,13 @@ FROM debian:buster-slim as builder ## Supports x86_64, x86, arm, and arm64 RUN apt-get update && apt-get install -y curl gnupg -RUN apt-key adv --keyserver pgp.mit.edu --recv-keys 0x1657198823e52a61 && \ +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.8.6 +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 debian:buster-slim -LABEL version="1.8.6" +LABEL version="1.4.4" LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts." # ZeroTier relies on UDP port 9993 diff --git a/ext/installfiles/linux/zerotier-one.te b/ext/installfiles/linux/zerotier-one.te deleted file mode 100644 index 978df0b1..00000000 --- a/ext/installfiles/linux/zerotier-one.te +++ /dev/null @@ -1,14 +0,0 @@ - -module zerotier-one 1.0; - -require { - type unconfined_t; - type initrc_t; - class memprotect mmap_zero; -} - -#============= initrc_t ============== -allow initrc_t self:memprotect mmap_zero; - -#============= unconfined_t ============== -allow unconfined_t self:memprotect mmap_zero; diff --git a/ext/installfiles/mac/ZeroTier One.pkgproj b/ext/installfiles/mac/ZeroTier One.pkgproj index cf6af8e7..c55ae733 100755 --- a/ext/installfiles/mac/ZeroTier One.pkgproj +++ b/ext/installfiles/mac/ZeroTier One.pkgproj @@ -37,24 +37,12 @@ 0 - BUNDLE_CAN_DOWNGRADE - - BUNDLE_POSTINSTALL_PATH - - PATH_TYPE - 0 - - BUNDLE_PREINSTALL_PATH - - PATH_TYPE - 0 - CHILDREN GID 80 PATH - ../../../../DesktopUI/ZeroTier.app + ../../../macui/build/Release/ZeroTier One.app PATH_TYPE 1 PERMISSIONS @@ -138,6 +126,34 @@ UID 0 + + BUNDLE_CAN_DOWNGRADE + + BUNDLE_POSTINSTALL_PATH + + PATH_TYPE + 0 + + BUNDLE_PREINSTALL_PATH + + PATH_TYPE + 0 + + CHILDREN + + GID + 0 + PATH + ../../bin/tap-mac/tap.kext + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + CHILDREN @@ -701,7 +717,7 @@ USE_HFS+_COMPRESSION VERSION - 1.14.1 + 1.4.6 TYPE 0 @@ -760,43 +776,6 @@ SHARED_SETTINGS_FOR_ALL_APPAREANCES - INSTALLATION TYPE - - HIERARCHIES - - INSTALLER - - LIST - - - CHILDREN - - DESCRIPTION - - OPTIONS - - HIDDEN - - STATE - 1 - - PACKAGE_UUID - 1B6AFC3A-9EA5-4401-83D4-37F06CD13CD6 - TITLE - - TYPE - 0 - UUID - 0FC7D07B-9BA9-4711-BB08-A05099C9E2B9 - - - REMOVED - - - - MODE - 0 - INSTALLATION_STEPS @@ -893,7 +872,7 @@ IC_REQUIREMENT_OS_DISTRIBUTION_TYPE 0 IC_REQUIREMENT_OS_MINIMUM_VERSION - 101300 + 101000 IC_REQUIREMENT_CHECK_TYPE 1 @@ -914,13 +893,6 @@ PROJECT_SETTINGS - ADVANCED_OPTIONS - - installer-script.options:hostArchitectures - - x86_64,arm64 - - BUILD_FORMAT 0 BUILD_PATH diff --git a/ext/installfiles/mac/launch.sh b/ext/installfiles/mac/launch.sh index ab274cbf..b02a6670 100755 --- a/ext/installfiles/mac/launch.sh +++ b/ext/installfiles/mac/launch.sh @@ -1,4 +1,3 @@ #!/bin/bash export PATH="/Library/Application Support/ZeroTier/One:/bin:/usr/bin:/sbin:/usr/sbin" -/usr/bin/killall MacEthernetTapAgent >>/dev/null 2>&1 exec zerotier-one diff --git a/ext/installfiles/mac/postinst.sh b/ext/installfiles/mac/postinst.sh index 707b4670..95301a4e 100755 --- a/ext/installfiles/mac/postinst.sh +++ b/ext/installfiles/mac/postinst.sh @@ -2,8 +2,32 @@ export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin +OSX_RELEASE=`sw_vers -productVersion | cut -d . -f 1,2` +DARWIN_MAJOR=`uname -r | cut -d . -f 1` + +launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 +sleep 0.5 + cd "/Library/Application Support/ZeroTier/One" +if [ "$OSX_RELEASE" = "10.7" ]; then + # OSX 10.7 cannot use the new tap driver since the new way of kext signing + # is not backward compatible. Pull the old one for 10.7 users and replace. + # We use https to fetch and check hash as an extra added measure. + rm -f tap.kext.10_7.tar.gz + curl -s https://download.zerotier.com/tap.kext.10_7.tar.gz >tap.kext.10_7.tar.gz + if [ -s tap.kext.10_7.tar.gz -a "`shasum -a 256 tap.kext.10_7.tar.gz | cut -d ' ' -f 1`" = "e133d4832cef571621d3618f417381b44f51a76ed625089fb4e545e65d3ef2a9" ]; then + rm -rf tap.kext + tar -xzf tap.kext.10_7.tar.gz + fi + rm -f tap.kext.10_7.tar.gz +fi + +rm -rf node.log node.log.old root-topology shutdownIfUnreadable autoupdate.log updates.d ui peers.save + +chown -R 0 tap.kext +chgrp -R 0 tap.kext + if [ ! -f authtoken.secret ]; then head -c 1024 /dev/urandom | md5 | head -c 24 >authtoken.secret chown 0 authtoken.secret @@ -11,39 +35,28 @@ if [ ! -f authtoken.secret ]; then chmod 0600 authtoken.secret fi -if [ -f zerotier-one.pid ]; then - kill `cat zerotier-one.pid` - sleep 1 - killall MacEthernetTapAgent - sleep 1 - killall -9 MacEthernetTapAgent - sleep 1 - if [ -f zerotier-one.pid ]; then - kill -9 `cat zerotier-one.pid` - rm -f zerotier-one.pid - fi -fi -launchctl load /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 -sleep 1 - rm -f zerotier-cli zerotier-idtool ln -sf zerotier-one zerotier-cli ln -sf zerotier-one zerotier-idtool -if [ ! -d /usr/local/bin ]; then - mkdir -p /usr/local/bin -fi +mkdir -p /usr/local/bin cd /usr/local/bin rm -f zerotier-cli zerotier-idtool ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-cli ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-idtool +if [ $DARWIN_MAJOR -le 16 ]; then + cd "/Library/Application Support/ZeroTier/One" + kextload -r . tap.kext >>/dev/null 2>&1 & + disown %1 +fi + +launchctl load /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 + +sleep 1 + if [ -f /tmp/zt1-gui-restart.tmp ]; then for u in `cat /tmp/zt1-gui-restart.tmp`; do - if [ -f '/Applications/ZeroTier One.app/Contents/MacOS/ZeroTier One' ]; then - su $u -c '/usr/bin/open /Applications/ZeroTier\ One.app &' >>/dev/null 2>&1 & - else - su $u -c '/usr/bin/open /Applications/ZeroTier.app &' >>/dev/null 2>&1 & - fi + su $u -c '/Applications/ZeroTier\ One.app/Contents/MacOS/ZeroTier\ One &' >>/dev/null 2>&1 & done fi rm -f /tmp/zt1-gui-restart.tmp diff --git a/ext/installfiles/mac/preinst.sh b/ext/installfiles/mac/preinst.sh index d2df6a3a..af2a9320 100755 --- a/ext/installfiles/mac/preinst.sh +++ b/ext/installfiles/mac/preinst.sh @@ -8,32 +8,32 @@ for i in `ps axuwww | tr -s ' ' ',' | grep -F '/Applications/ZeroTier,One.app' | p=`echo $i | cut -d , -f 2` if [ ! -z "$u" -a "0$p" -gt 0 ]; then kill $p >>/dev/null 2>&1 - sleep 0.5 - kill -9 $p >>/dev/null 2>&1 - echo "$u" >>/tmp/zt1-gui-restart.tmp - fi -done -for i in `ps axuwww | tr -s ' ' ',' | grep -F '/Applications/ZeroTier.app' | grep -F -v grep | cut -d , -f 1,2 | xargs`; do - u=`echo $i | cut -d , -f 1` - p=`echo $i | cut -d , -f 2` - if [ ! -z "$u" -a "0$p" -gt 0 ]; then - kill $p >>/dev/null 2>&1 - sleep 0.5 + sleep 0.2 kill -9 $p >>/dev/null 2>&1 echo "$u" >>/tmp/zt1-gui-restart.tmp fi done chmod 0600 /tmp/zt1-gui-restart.tmp -cd "/Applications" -rm -rf "ZeroTier One.app" -rm -rf "ZeroTier.app" - -if [ -d '/Library/Application Support/ZeroTier/One' ]; then - cd '/Library/Application Support/ZeroTier/One' - # ensure that file locking doesn't cause issues with replacing the binary - rm -f zerotier-one - rm -f MacEthernetTapAgent +if [ -f /Library/LaunchDaemons/com.zerotier.one.plist ]; then + launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1 fi +sleep 1 + +if [ -d "/Library/Application Support/ZeroTier/One" ]; then + cd "/Library/Application Support/ZeroTier/One" + if [ -f "zerotier-one.pid" ]; then + ztpid=`cat zerotier-one.pid` + if [ "$ztpid" -gt "0" ]; then + kill `cat zerotier-one.pid` + fi + fi +fi + +sleep 1 + +cd "/Applications" +rm -rf "ZeroTier One.app" + exit 0 diff --git a/ext/installfiles/mac/uninstall.sh b/ext/installfiles/mac/uninstall.sh index 4b6abe13..52c09b63 100755 --- a/ext/installfiles/mac/uninstall.sh +++ b/ext/installfiles/mac/uninstall.sh @@ -21,10 +21,12 @@ killall -TERM zerotier-one >>/dev/null 2>&1 sleep 1 killall -KILL zerotier-one >>/dev/null 2>&1 +echo "Making sure kext is unloaded..." +kextunload '/Library/Application Support/ZeroTier/One/tap.kext' >>/dev/null 2>&1 + echo "Removing ZeroTier One files..." rm -rf '/Applications/ZeroTier One.app' -rm -rf '/Applications/ZeroTier.app' rm -f '/usr/local/bin/zerotier-one' '/usr/local/bin/zerotier-idtool' '/usr/local/bin/zerotier-cli' '/Library/LaunchDaemons/com.zerotier.one.plist' cd '/Library/Application Support/ZeroTier/One' diff --git a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip index 3c3d6a41..7ff1a05e 100644 --- a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip +++ b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x64).aip @@ -1,187 +1,184 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip index 50d5f557..ef3d58cc 100644 --- a/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip +++ b/ext/installfiles/windows/ZeroTier One Virtual Network Port (NDIS6_x86).aip @@ -1,188 +1,185 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index 0870201e..61b6ec33 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -1,15 +1,17 @@ - + - + + - + - + + @@ -22,115 +24,124 @@ + - + - + + - + - - - - - - + + + + + - + - + + - - - - - - - - + + + + + + - - + + - - + + - - - - - - + + - - + - - - - + + + - - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + + + + + + + - - + + + + + + + + + + - + - - - - + + + + @@ -139,7 +150,6 @@ - @@ -147,6 +157,11 @@ + + + + + @@ -175,43 +190,23 @@ + + + - + - - - - - - - - - - - - - - - - - - - - - - - - + @@ -229,48 +224,50 @@ - - - - + + + + + - - - - - - - - + + + + + + + + - - + + + - + @@ -280,13 +277,14 @@ + - + - + @@ -299,43 +297,24 @@ - - + - - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + @@ -343,24 +322,26 @@ - - - + + + - - - - + + + + + + - + @@ -368,95 +349,67 @@ - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - - + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - + + @@ -467,8 +420,7 @@ - - + @@ -477,6 +429,10 @@ + + + + @@ -498,28 +454,28 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/installfiles/windows/ZeroTier One.back.aip b/ext/installfiles/windows/ZeroTier One.back.aip deleted file mode 100644 index 9ad81827..00000000 --- a/ext/installfiles/windows/ZeroTier One.back.aip +++ /dev/null @@ -1,558 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ext/nlohmann/LICENSE.MIT b/ext/json/LICENSE.MIT similarity index 100% rename from ext/nlohmann/LICENSE.MIT rename to ext/json/LICENSE.MIT diff --git a/ext/nlohmann/README.md b/ext/json/README.md similarity index 100% rename from ext/nlohmann/README.md rename to ext/json/README.md diff --git a/ext/nlohmann/json.hpp b/ext/json/json.hpp similarity index 51% rename from ext/nlohmann/json.hpp rename to ext/json/json.hpp index 8959265d..b80386f3 100644 --- a/ext/nlohmann/json.hpp +++ b/ext/json/json.hpp @@ -1,12 +1,12 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.10.2 +| | |__ | | | | | | version 3.2.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . SPDX-License-Identifier: MIT -Copyright (c) 2013-2019 Niels Lohmann . +Copyright (c) 2013-2018 Niels Lohmann . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -27,2194 +27,94 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef INCLUDE_NLOHMANN_JSON_HPP_ -#define INCLUDE_NLOHMANN_JSON_HPP_ +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 10 -#define NLOHMANN_JSON_VERSION_PATCH 2 +#define NLOHMANN_JSON_VERSION_MINOR 2 +#define NLOHMANN_JSON_VERSION_PATCH 0 #include // all_of, find, for_each +#include // assert +#include // and, not, or #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list -#ifndef JSON_NO_IO - #include // istream, ostream -#endif // JSON_NO_IO -#include // random_access_iterator_tag -#include // unique_ptr +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag #include // accumulate #include // string, stoi, to_string #include // declval, forward, move, pair, swap -#include // vector -// #include +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP - -#include -#include - -// #include - - -#include // transform -#include // array -#include // forward_list -#include // inserter, front_inserter, end +#include // int64_t, uint64_t #include // map +#include // allocator #include // string -#include // tuple, make_tuple -#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible -#include // unordered_map -#include // pair, declval -#include // valarray - -// #include - - -#include // exception -#include // runtime_error -#include // to_string #include // vector -// #include - - -#include // array -#include // size_t -#include // uint8_t -#include // string - +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ namespace nlohmann { -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; /*! -@brief the JSON type enumeration +@brief JSON Pointer -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) -@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. @since version 1.0.0 */ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - binary, ///< binary array (ordered collection of bytes) - discarded ///< discarded by the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string < binary -- furthermore, each type is not smaller than itself -- discarded values are not comparable -- binary is represented as a b"" string in python and directly comparable to a - string; however, making a binary array directly comparable with a string would - be surprising behavior in a JSON file. - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, - 6 /* binary */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +using json = basic_json<>; } -} // namespace detail -} // namespace nlohmann -// #include +#endif - -#include // #include -#include // pair -// #include - - -/* Hedley - https://nemequ.github.io/hedley - * Created by Evan Nemerson - * - * To the extent possible under law, the author(s) have dedicated all - * copyright and related and neighboring rights to this software to - * the public domain worldwide. This software is distributed without - * any warranty. - * - * For details, see . - * SPDX-License-Identifier: CC0-1.0 - */ - -#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) -#if defined(JSON_HEDLEY_VERSION) - #undef JSON_HEDLEY_VERSION -#endif -#define JSON_HEDLEY_VERSION 15 - -#if defined(JSON_HEDLEY_STRINGIFY_EX) - #undef JSON_HEDLEY_STRINGIFY_EX -#endif -#define JSON_HEDLEY_STRINGIFY_EX(x) #x - -#if defined(JSON_HEDLEY_STRINGIFY) - #undef JSON_HEDLEY_STRINGIFY -#endif -#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) - -#if defined(JSON_HEDLEY_CONCAT_EX) - #undef JSON_HEDLEY_CONCAT_EX -#endif -#define JSON_HEDLEY_CONCAT_EX(a,b) a##b - -#if defined(JSON_HEDLEY_CONCAT) - #undef JSON_HEDLEY_CONCAT -#endif -#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) - -#if defined(JSON_HEDLEY_CONCAT3_EX) - #undef JSON_HEDLEY_CONCAT3_EX -#endif -#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c - -#if defined(JSON_HEDLEY_CONCAT3) - #undef JSON_HEDLEY_CONCAT3 -#endif -#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) - -#if defined(JSON_HEDLEY_VERSION_ENCODE) - #undef JSON_HEDLEY_VERSION_ENCODE -#endif -#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) - -#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) - #undef JSON_HEDLEY_VERSION_DECODE_MAJOR -#endif -#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) - -#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) - #undef JSON_HEDLEY_VERSION_DECODE_MINOR -#endif -#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) - -#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) - #undef JSON_HEDLEY_VERSION_DECODE_REVISION -#endif -#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) - -#if defined(JSON_HEDLEY_GNUC_VERSION) - #undef JSON_HEDLEY_GNUC_VERSION -#endif -#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#elif defined(__GNUC__) - #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) -#endif - -#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) - #undef JSON_HEDLEY_GNUC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_GNUC_VERSION) - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_MSVC_VERSION) - #undef JSON_HEDLEY_MSVC_VERSION -#endif -#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) -#elif defined(_MSC_FULL_VER) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) -#elif defined(_MSC_VER) && !defined(__ICL) - #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) -#endif - -#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) - #undef JSON_HEDLEY_MSVC_VERSION_CHECK -#endif -#if !defined(JSON_HEDLEY_MSVC_VERSION) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) -#elif defined(_MSC_VER) && (_MSC_VER >= 1400) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) -#elif defined(_MSC_VER) && (_MSC_VER >= 1200) - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) -#else - #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) -#endif - -#if defined(JSON_HEDLEY_INTEL_VERSION) - #undef JSON_HEDLEY_INTEL_VERSION -#endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) -#elif defined(__INTEL_COMPILER) && !defined(__ICL) - #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) -#endif - -#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_INTEL_VERSION) - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_INTEL_CL_VERSION) - #undef JSON_HEDLEY_INTEL_CL_VERSION -#endif -#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) - #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) -#endif - -#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) - #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_INTEL_CL_VERSION) - #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_PGI_VERSION) - #undef JSON_HEDLEY_PGI_VERSION -#endif -#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) - #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) -#endif - -#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) - #undef JSON_HEDLEY_PGI_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_PGI_VERSION) - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_SUNPRO_VERSION) - #undef JSON_HEDLEY_SUNPRO_VERSION -#endif -#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) -#elif defined(__SUNPRO_C) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) -#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) -#elif defined(__SUNPRO_CC) - #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) -#endif - -#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) - #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_SUNPRO_VERSION) - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION -#endif -#if defined(__EMSCRIPTEN__) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) -#endif - -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) - #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_ARM_VERSION) - #undef JSON_HEDLEY_ARM_VERSION -#endif -#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) -#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) - #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) -#endif - -#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) - #undef JSON_HEDLEY_ARM_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_ARM_VERSION) - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_IBM_VERSION) - #undef JSON_HEDLEY_IBM_VERSION -#endif -#if defined(__ibmxl__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) -#elif defined(__xlC__) && defined(__xlC_ver__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) -#elif defined(__xlC__) - #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) -#endif - -#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) - #undef JSON_HEDLEY_IBM_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_IBM_VERSION) - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_VERSION) - #undef JSON_HEDLEY_TI_VERSION -#endif -#if \ - defined(__TI_COMPILER_VERSION__) && \ - ( \ - defined(__TMS470__) || defined(__TI_ARM__) || \ - defined(__MSP430__) || \ - defined(__TMS320C2000__) \ - ) -#if (__TI_COMPILER_VERSION__ >= 16000000) - #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif -#endif - -#if defined(JSON_HEDLEY_TI_VERSION_CHECK) - #undef JSON_HEDLEY_TI_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_VERSION) - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL2000_VERSION) - #undef JSON_HEDLEY_TI_CL2000_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) - #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL2000_VERSION) - #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL430_VERSION) - #undef JSON_HEDLEY_TI_CL430_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) - #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL430_VERSION) - #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) - #undef JSON_HEDLEY_TI_ARMCL_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) - #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) - #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) - #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL6X_VERSION) - #undef JSON_HEDLEY_TI_CL6X_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) - #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL6X_VERSION) - #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CL7X_VERSION) - #undef JSON_HEDLEY_TI_CL7X_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) - #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CL7X_VERSION) - #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) - #undef JSON_HEDLEY_TI_CLPRU_VERSION -#endif -#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) - #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) -#endif - -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) - #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) - #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_CRAY_VERSION) - #undef JSON_HEDLEY_CRAY_VERSION -#endif -#if defined(_CRAYC) - #if defined(_RELEASE_PATCHLEVEL) - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) - #else - #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) - #endif -#endif - -#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) - #undef JSON_HEDLEY_CRAY_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_CRAY_VERSION) - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_IAR_VERSION) - #undef JSON_HEDLEY_IAR_VERSION -#endif -#if defined(__IAR_SYSTEMS_ICC__) - #if __VER__ > 1000 - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) - #else - #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) - #endif -#endif - -#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) - #undef JSON_HEDLEY_IAR_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_IAR_VERSION) - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_TINYC_VERSION) - #undef JSON_HEDLEY_TINYC_VERSION -#endif -#if defined(__TINYC__) - #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) -#endif - -#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) - #undef JSON_HEDLEY_TINYC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_DMC_VERSION) - #undef JSON_HEDLEY_DMC_VERSION -#endif -#if defined(__DMC__) - #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) -#endif - -#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) - #undef JSON_HEDLEY_DMC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_DMC_VERSION) - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_COMPCERT_VERSION) - #undef JSON_HEDLEY_COMPCERT_VERSION -#endif -#if defined(__COMPCERT_VERSION__) - #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) -#endif - -#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) - #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_COMPCERT_VERSION) - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_PELLES_VERSION) - #undef JSON_HEDLEY_PELLES_VERSION -#endif -#if defined(__POCC__) - #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) -#endif - -#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) - #undef JSON_HEDLEY_PELLES_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_PELLES_VERSION) - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_MCST_LCC_VERSION) - #undef JSON_HEDLEY_MCST_LCC_VERSION -#endif -#if defined(__LCC__) && defined(__LCC_MINOR__) - #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) -#endif - -#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) - #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_MCST_LCC_VERSION) - #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_GCC_VERSION) - #undef JSON_HEDLEY_GCC_VERSION -#endif -#if \ - defined(JSON_HEDLEY_GNUC_VERSION) && \ - !defined(__clang__) && \ - !defined(JSON_HEDLEY_INTEL_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_ARM_VERSION) && \ - !defined(JSON_HEDLEY_CRAY_VERSION) && \ - !defined(JSON_HEDLEY_TI_VERSION) && \ - !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ - !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ - !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ - !defined(__COMPCERT__) && \ - !defined(JSON_HEDLEY_MCST_LCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION -#endif - -#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_VERSION_CHECK -#endif -#if defined(JSON_HEDLEY_GCC_VERSION) - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) -#else - #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) -#endif - -#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_ATTRIBUTE -#endif -#if \ - defined(__has_attribute) && \ - ( \ - (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ - ) -# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) -#else -# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE -#endif -#if defined(__has_attribute) - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE -#endif -#if defined(__has_attribute) - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE -#endif -#if \ - defined(__has_cpp_attribute) && \ - defined(__cplusplus) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) - #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS -#endif -#if !defined(__cplusplus) || !defined(__has_cpp_attribute) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#elif \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_IAR_VERSION) && \ - (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ - (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) -#else - #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE -#endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE -#endif -#if defined(__has_cpp_attribute) && defined(__cplusplus) - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_BUILTIN) - #undef JSON_HEDLEY_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) -#else - #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) - #undef JSON_HEDLEY_GNUC_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) -#else - #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) - #undef JSON_HEDLEY_GCC_HAS_BUILTIN -#endif -#if defined(__has_builtin) - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) -#else - #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_FEATURE) - #undef JSON_HEDLEY_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) -#else - #define JSON_HEDLEY_HAS_FEATURE(feature) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) - #undef JSON_HEDLEY_GNUC_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) -#else - #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) - #undef JSON_HEDLEY_GCC_HAS_FEATURE -#endif -#if defined(__has_feature) - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) -#else - #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_EXTENSION) - #undef JSON_HEDLEY_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) -#else - #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) - #undef JSON_HEDLEY_GNUC_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) -#else - #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) - #undef JSON_HEDLEY_GCC_HAS_EXTENSION -#endif -#if defined(__has_extension) - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) -#else - #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE -#endif -#if defined(__has_declspec_attribute) - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) -#else - #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_HAS_WARNING) - #undef JSON_HEDLEY_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) -#else - #define JSON_HEDLEY_HAS_WARNING(warning) (0) -#endif - -#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) - #undef JSON_HEDLEY_GNUC_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else - #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_GCC_HAS_WARNING) - #undef JSON_HEDLEY_GCC_HAS_WARNING -#endif -#if defined(__has_warning) - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) -#else - #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__clang__) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ - (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) - #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_PRAGMA(value) __pragma(value) -#else - #define JSON_HEDLEY_PRAGMA(value) -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) - #undef JSON_HEDLEY_DIAGNOSTIC_PUSH -#endif -#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) - #undef JSON_HEDLEY_DIAGNOSTIC_POP -#endif -#if defined(__clang__) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) - #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) -#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") - #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_PUSH - #define JSON_HEDLEY_DIAGNOSTIC_POP -#endif - -/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ -#endif -#if defined(__cplusplus) -# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") -# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") -# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# endif -# else -# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ - xpr \ - JSON_HEDLEY_DIAGNOSTIC_POP -# endif -# endif -#endif -#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x -#endif - -#if defined(JSON_HEDLEY_CONST_CAST) - #undef JSON_HEDLEY_CONST_CAST -#endif -#if defined(__cplusplus) -# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) -#elif \ - JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_REINTERPRET_CAST) - #undef JSON_HEDLEY_REINTERPRET_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) -#else - #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_STATIC_CAST) - #undef JSON_HEDLEY_STATIC_CAST -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) -#else - #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) -#endif - -#if defined(JSON_HEDLEY_CPP_CAST) - #undef JSON_HEDLEY_CPP_CAST -#endif -#if defined(__cplusplus) -# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") -# define JSON_HEDLEY_CPP_CAST(T, expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - ((T) (expr)) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) -# define JSON_HEDLEY_CPP_CAST(T, expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("diag_suppress=Pe137") \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) -# endif -#else -# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") -#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") -#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") -#elif \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") -#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL -#endif - -#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) - #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") -#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) -#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") -#else - #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION -#endif - -#if defined(JSON_HEDLEY_DEPRECATED) - #undef JSON_HEDLEY_DEPRECATED -#endif -#if defined(JSON_HEDLEY_DEPRECATED_FOR) - #undef JSON_HEDLEY_DEPRECATED_FOR -#endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) -#elif \ - (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) -#elif defined(__cplusplus) && (__cplusplus >= 201402L) - #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") -#else - #define JSON_HEDLEY_DEPRECATED(since) - #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) -#endif - -#if defined(JSON_HEDLEY_UNAVAILABLE) - #undef JSON_HEDLEY_UNAVAILABLE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) -#else - #define JSON_HEDLEY_UNAVAILABLE(available_since) -#endif - -#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT -#endif -#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) - #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) -#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) - #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) -#elif defined(_Check_return_) /* SAL */ - #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ -#else - #define JSON_HEDLEY_WARN_UNUSED_RESULT - #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) -#endif - -#if defined(JSON_HEDLEY_SENTINEL) - #undef JSON_HEDLEY_SENTINEL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) -#else - #define JSON_HEDLEY_SENTINEL(position) -#endif - -#if defined(JSON_HEDLEY_NO_RETURN) - #undef JSON_HEDLEY_NO_RETURN -#endif -#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NO_RETURN __noreturn -#elif \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - #define JSON_HEDLEY_NO_RETURN _Noreturn -#elif defined(__cplusplus) && (__cplusplus >= 201103L) - #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) -#else - #define JSON_HEDLEY_NO_RETURN -#endif - -#if defined(JSON_HEDLEY_NO_ESCAPE) - #undef JSON_HEDLEY_NO_ESCAPE -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) - #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) -#else - #define JSON_HEDLEY_NO_ESCAPE -#endif - -#if defined(JSON_HEDLEY_UNREACHABLE) - #undef JSON_HEDLEY_UNREACHABLE -#endif -#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) - #undef JSON_HEDLEY_UNREACHABLE_RETURN -#endif -#if defined(JSON_HEDLEY_ASSUME) - #undef JSON_HEDLEY_ASSUME -#endif -#if \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_ASSUME(expr) __assume(expr) -#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) - #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) -#elif \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) - #if defined(__cplusplus) - #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) - #else - #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) - #endif -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() -#elif defined(JSON_HEDLEY_ASSUME) - #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) -#endif -#if !defined(JSON_HEDLEY_ASSUME) - #if defined(JSON_HEDLEY_UNREACHABLE) - #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) - #else - #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) - #endif -#endif -#if defined(JSON_HEDLEY_UNREACHABLE) - #if \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) - #else - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() - #endif -#else - #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) -#endif -#if !defined(JSON_HEDLEY_UNREACHABLE) - #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) -#endif - -JSON_HEDLEY_DIAGNOSTIC_PUSH -#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") - #pragma clang diagnostic ignored "-Wpedantic" -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) - #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" -#endif -#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) - #if defined(__clang__) - #pragma clang diagnostic ignored "-Wvariadic-macros" - #elif defined(JSON_HEDLEY_GCC_VERSION) - #pragma GCC diagnostic ignored "-Wvariadic-macros" - #endif -#endif -#if defined(JSON_HEDLEY_NON_NULL) - #undef JSON_HEDLEY_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) -#else - #define JSON_HEDLEY_NON_NULL(...) -#endif -JSON_HEDLEY_DIAGNOSTIC_POP - -#if defined(JSON_HEDLEY_PRINTF_FORMAT) - #undef JSON_HEDLEY_PRINTF_FORMAT -#endif -#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) -#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) -#elif \ - JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) -#else - #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) -#endif - -#if defined(JSON_HEDLEY_CONSTEXPR) - #undef JSON_HEDLEY_CONSTEXPR -#endif -#if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) - #endif -#endif -#if !defined(JSON_HEDLEY_CONSTEXPR) - #define JSON_HEDLEY_CONSTEXPR -#endif - -#if defined(JSON_HEDLEY_PREDICT) - #undef JSON_HEDLEY_PREDICT -#endif -#if defined(JSON_HEDLEY_LIKELY) - #undef JSON_HEDLEY_LIKELY -#endif -#if defined(JSON_HEDLEY_UNLIKELY) - #undef JSON_HEDLEY_UNLIKELY -#endif -#if defined(JSON_HEDLEY_UNPREDICTABLE) - #undef JSON_HEDLEY_UNPREDICTABLE -#endif -#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) - #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) -#endif -#if \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) -#elif \ - (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ - (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ - (__extension__ ({ \ - double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ - })) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ - (__extension__ ({ \ - double hedley_probability_ = (probability); \ - ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ - })) -# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) -# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -#else -# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) -# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) -# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) -# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) -#endif -#if !defined(JSON_HEDLEY_UNPREDICTABLE) - #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) -#endif - -#if defined(JSON_HEDLEY_MALLOC) - #undef JSON_HEDLEY_MALLOC -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_MALLOC __declspec(restrict) -#else - #define JSON_HEDLEY_MALLOC -#endif - -#if defined(JSON_HEDLEY_PURE) - #undef JSON_HEDLEY_PURE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PURE __attribute__((__pure__)) -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) -# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") -#elif defined(__cplusplus) && \ - ( \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ - ) -# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") -#else -# define JSON_HEDLEY_PURE -#endif - -#if defined(JSON_HEDLEY_CONST) - #undef JSON_HEDLEY_CONST -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_CONST __attribute__((__const__)) -#elif \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) - #define JSON_HEDLEY_CONST _Pragma("no_side_effect") -#else - #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE -#endif - -#if defined(JSON_HEDLEY_RESTRICT) - #undef JSON_HEDLEY_RESTRICT -#endif -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT restrict -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ - defined(__clang__) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_RESTRICT __restrict -#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) - #define JSON_HEDLEY_RESTRICT _Restrict -#else - #define JSON_HEDLEY_RESTRICT -#endif - -#if defined(JSON_HEDLEY_INLINE) - #undef JSON_HEDLEY_INLINE -#endif -#if \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - (defined(__cplusplus) && (__cplusplus >= 199711L)) - #define JSON_HEDLEY_INLINE inline -#elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) - #define JSON_HEDLEY_INLINE __inline__ -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_INLINE __inline -#else - #define JSON_HEDLEY_INLINE -#endif - -#if defined(JSON_HEDLEY_ALWAYS_INLINE) - #undef JSON_HEDLEY_ALWAYS_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) -# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_ALWAYS_INLINE __forceinline -#elif defined(__cplusplus) && \ - ( \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ - ) -# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") -#else -# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE -#endif - -#if defined(JSON_HEDLEY_NEVER_INLINE) - #undef JSON_HEDLEY_NEVER_INLINE -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ - JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ - (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ - (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ - (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ - JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ - JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ - JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") -#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) - #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") -#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) - #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) - #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) -#else - #define JSON_HEDLEY_NEVER_INLINE -#endif - -#if defined(JSON_HEDLEY_PRIVATE) - #undef JSON_HEDLEY_PRIVATE -#endif -#if defined(JSON_HEDLEY_PUBLIC) - #undef JSON_HEDLEY_PUBLIC -#endif -#if defined(JSON_HEDLEY_IMPORT) - #undef JSON_HEDLEY_IMPORT -#endif -#if defined(_WIN32) || defined(__CYGWIN__) -# define JSON_HEDLEY_PRIVATE -# define JSON_HEDLEY_PUBLIC __declspec(dllexport) -# define JSON_HEDLEY_IMPORT __declspec(dllimport) -#else -# if \ - JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - ( \ - defined(__TI_EABI__) && \ - ( \ - (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ - ) \ - ) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) -# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) -# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) -# else -# define JSON_HEDLEY_PRIVATE -# define JSON_HEDLEY_PUBLIC -# endif -# define JSON_HEDLEY_IMPORT extern -#endif - -#if defined(JSON_HEDLEY_NO_THROW) - #undef JSON_HEDLEY_NO_THROW -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) - #define JSON_HEDLEY_NO_THROW __declspec(nothrow) -#else - #define JSON_HEDLEY_NO_THROW -#endif - -#if defined(JSON_HEDLEY_FALL_THROUGH) - #undef JSON_HEDLEY_FALL_THROUGH -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) -#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) - #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) -#elif defined(__fallthrough) /* SAL */ - #define JSON_HEDLEY_FALL_THROUGH __fallthrough -#else - #define JSON_HEDLEY_FALL_THROUGH -#endif - -#if defined(JSON_HEDLEY_RETURNS_NON_NULL) - #undef JSON_HEDLEY_RETURNS_NON_NULL -#endif -#if \ - JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) -#elif defined(_Ret_notnull_) /* SAL */ - #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ -#else - #define JSON_HEDLEY_RETURNS_NON_NULL -#endif - -#if defined(JSON_HEDLEY_ARRAY_PARAM) - #undef JSON_HEDLEY_ARRAY_PARAM -#endif -#if \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ - !defined(__STDC_NO_VLA__) && \ - !defined(__cplusplus) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_TINYC_VERSION) - #define JSON_HEDLEY_ARRAY_PARAM(name) (name) -#else - #define JSON_HEDLEY_ARRAY_PARAM(name) -#endif - -#if defined(JSON_HEDLEY_IS_CONSTANT) - #undef JSON_HEDLEY_IS_CONSTANT -#endif -#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) - #undef JSON_HEDLEY_REQUIRE_CONSTEXPR -#endif -/* JSON_HEDLEY_IS_CONSTEXPR_ is for - HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ -#if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #undef JSON_HEDLEY_IS_CONSTEXPR_ -#endif -#if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ - (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) - #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) -#endif -#if !defined(__cplusplus) -# if \ - JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ - JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ - JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) -#if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) -#else - #include - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) -#endif -# elif \ - ( \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ - !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ - !defined(JSON_HEDLEY_PGI_VERSION) && \ - !defined(JSON_HEDLEY_IAR_VERSION)) || \ - (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ - JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ - JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) -#if defined(__INTPTR_TYPE__) - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) -#else - #include - #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) -#endif -# elif \ - defined(JSON_HEDLEY_GCC_VERSION) || \ - defined(JSON_HEDLEY_INTEL_VERSION) || \ - defined(JSON_HEDLEY_TINYC_VERSION) || \ - defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ - JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ - defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ - defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ - defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ - defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ - defined(__clang__) -# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ - sizeof(void) != \ - sizeof(*( \ - 1 ? \ - ((void*) ((expr) * 0L) ) : \ -((struct { char v[sizeof(void) * 2]; } *) 1) \ - ) \ - ) \ - ) -# endif -#endif -#if defined(JSON_HEDLEY_IS_CONSTEXPR_) - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) -#else - #if !defined(JSON_HEDLEY_IS_CONSTANT) - #define JSON_HEDLEY_IS_CONSTANT(expr) (0) - #endif - #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) -#endif - -#if defined(JSON_HEDLEY_BEGIN_C_DECLS) - #undef JSON_HEDLEY_BEGIN_C_DECLS -#endif -#if defined(JSON_HEDLEY_END_C_DECLS) - #undef JSON_HEDLEY_END_C_DECLS -#endif -#if defined(JSON_HEDLEY_C_DECL) - #undef JSON_HEDLEY_C_DECL -#endif -#if defined(__cplusplus) - #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { - #define JSON_HEDLEY_END_C_DECLS } - #define JSON_HEDLEY_C_DECL extern "C" -#else - #define JSON_HEDLEY_BEGIN_C_DECLS - #define JSON_HEDLEY_END_C_DECLS - #define JSON_HEDLEY_C_DECL -#endif - -#if defined(JSON_HEDLEY_STATIC_ASSERT) - #undef JSON_HEDLEY_STATIC_ASSERT -#endif -#if \ - !defined(__cplusplus) && ( \ - (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ - (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ - JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ - defined(_Static_assert) \ - ) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) -#elif \ - (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ - JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) -#else -# define JSON_HEDLEY_STATIC_ASSERT(expr, message) -#endif - -#if defined(JSON_HEDLEY_NULL) - #undef JSON_HEDLEY_NULL -#endif -#if defined(__cplusplus) - #if __cplusplus >= 201103L - #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) - #elif defined(NULL) - #define JSON_HEDLEY_NULL NULL - #else - #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) - #endif -#elif defined(NULL) - #define JSON_HEDLEY_NULL NULL -#else - #define JSON_HEDLEY_NULL ((void*) 0) -#endif - -#if defined(JSON_HEDLEY_MESSAGE) - #undef JSON_HEDLEY_MESSAGE -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_MESSAGE(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(message msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) -#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) -#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) -# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#else -# define JSON_HEDLEY_MESSAGE(msg) -#endif - -#if defined(JSON_HEDLEY_WARNING) - #undef JSON_HEDLEY_WARNING -#endif -#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") -# define JSON_HEDLEY_WARNING(msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ - JSON_HEDLEY_PRAGMA(clang warning msg) \ - JSON_HEDLEY_DIAGNOSTIC_POP -#elif \ - JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ - JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ - JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) -#elif \ - JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) -#else -# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) -#endif - -#if defined(JSON_HEDLEY_REQUIRE) - #undef JSON_HEDLEY_REQUIRE -#endif -#if defined(JSON_HEDLEY_REQUIRE_MSG) - #undef JSON_HEDLEY_REQUIRE_MSG -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) -# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") -# define JSON_HEDLEY_REQUIRE(expr) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), #expr, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ - __attribute__((diagnose_if(!(expr), msg, "error"))) \ - JSON_HEDLEY_DIAGNOSTIC_POP -# else -# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) -# endif -#else -# define JSON_HEDLEY_REQUIRE(expr) -# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) -#endif - -#if defined(JSON_HEDLEY_FLAGS) - #undef JSON_HEDLEY_FLAGS -#endif -#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) - #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) -#else - #define JSON_HEDLEY_FLAGS -#endif - -#if defined(JSON_HEDLEY_FLAGS_CAST) - #undef JSON_HEDLEY_FLAGS_CAST -#endif -#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) -# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ - JSON_HEDLEY_DIAGNOSTIC_PUSH \ - _Pragma("warning(disable:188)") \ - ((T) (expr)); \ - JSON_HEDLEY_DIAGNOSTIC_POP \ - })) -#else -# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) -#endif - -#if defined(JSON_HEDLEY_EMPTY_BASES) - #undef JSON_HEDLEY_EMPTY_BASES -#endif -#if \ - (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ - JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) - #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) -#else - #define JSON_HEDLEY_EMPTY_BASES -#endif - -/* Remaining macros are deprecated. */ - -#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) - #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK -#endif -#if defined(__clang__) - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) -#else - #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) -#endif - -#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) - #undef JSON_HEDLEY_CLANG_HAS_BUILTIN -#endif -#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) - -#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) - #undef JSON_HEDLEY_CLANG_HAS_FEATURE -#endif -#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) - -#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) - #undef JSON_HEDLEY_CLANG_HAS_EXTENSION -#endif -#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) - -#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) - #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE -#endif -#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) - -#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) - #undef JSON_HEDLEY_CLANG_HAS_WARNING -#endif -#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) - -#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ - - // This file contains all internal macro definitions // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them @@ -2225,34 +125,31 @@ JSON_HEDLEY_DIAGNOSTIC_POP #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif #endif -// C++ language standard detection -// if the user manually specified the used c++ version this is skipped -#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) - #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) - #define JSON_HAS_CPP_20 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 - #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 - #endif - // the cpp 11 flag is always specified because it is the minimal required version - #define JSON_HAS_CPP_11 +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" #endif // disable documentation warnings on clang #if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdocumentation" - #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED #endif // allow to disable exceptions @@ -2262,7 +159,6 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_CATCH(exception) catch(exception) #define JSON_INTERNAL_CATCH(exception) catch(exception) #else - #include #define JSON_THROW(exception) std::abort() #define JSON_TRY if(true) #define JSON_CATCH(exception) if(false) @@ -2281,7 +177,6 @@ JSON_HEDLEY_DIAGNOSTIC_POP #if defined(JSON_CATCH_USER) #undef JSON_CATCH #define JSON_CATCH JSON_CATCH_USER - #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_CATCH_USER #endif #if defined(JSON_INTERNAL_CATCH_USER) @@ -2289,49 +184,22 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif -// allow to override assert -#if !defined(JSON_ASSERT) - #include // assert - #define JSON_ASSERT(x) assert(x) -#endif - -// allow to access some private functions (needed by the test suite) -#if defined(JSON_TESTS_PRIVATE) - #define JSON_PRIVATE_UNLESS_TESTED public +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #else - #define JSON_PRIVATE_UNLESS_TESTED private + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x #endif -/*! -@brief macro to briefly define a mapping between an enum and JSON -@def NLOHMANN_JSON_SERIALIZE_ENUM -@since version 3.4.0 -*/ -#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ - template \ - inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [e](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.first == e; \ - }); \ - j = ((it != std::end(m)) ? it : std::begin(m))->second; \ - } \ - template \ - inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ - { \ - static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ - static const std::pair m[] = __VA_ARGS__; \ - auto it = std::find_if(std::begin(m), std::end(m), \ - [&j](const std::pair& ej_pair) -> bool \ - { \ - return ej_pair.second == j; \ - }); \ - e = ((it != std::end(m)) ? it : std::begin(m))->first; \ - } +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif // Ugly macros to avoid uglier copy-paste when specializing basic_json. They // may be removed in the future once the class is split. @@ -2342,274 +210,337 @@ JSON_HEDLEY_DIAGNOSTIC_POP class StringType, class BooleanType, class NumberIntegerType, \ class NumberUnsignedType, class NumberFloatType, \ template class AllocatorType, \ - template class JSONSerializer, \ - class BinaryType> + template class JSONSerializer> #define NLOHMANN_BASIC_JSON_TPL \ basic_json - -// Macros to simplify conversion from/to types - -#define NLOHMANN_JSON_EXPAND( x ) x -#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME -#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ - NLOHMANN_JSON_PASTE64, \ - NLOHMANN_JSON_PASTE63, \ - NLOHMANN_JSON_PASTE62, \ - NLOHMANN_JSON_PASTE61, \ - NLOHMANN_JSON_PASTE60, \ - NLOHMANN_JSON_PASTE59, \ - NLOHMANN_JSON_PASTE58, \ - NLOHMANN_JSON_PASTE57, \ - NLOHMANN_JSON_PASTE56, \ - NLOHMANN_JSON_PASTE55, \ - NLOHMANN_JSON_PASTE54, \ - NLOHMANN_JSON_PASTE53, \ - NLOHMANN_JSON_PASTE52, \ - NLOHMANN_JSON_PASTE51, \ - NLOHMANN_JSON_PASTE50, \ - NLOHMANN_JSON_PASTE49, \ - NLOHMANN_JSON_PASTE48, \ - NLOHMANN_JSON_PASTE47, \ - NLOHMANN_JSON_PASTE46, \ - NLOHMANN_JSON_PASTE45, \ - NLOHMANN_JSON_PASTE44, \ - NLOHMANN_JSON_PASTE43, \ - NLOHMANN_JSON_PASTE42, \ - NLOHMANN_JSON_PASTE41, \ - NLOHMANN_JSON_PASTE40, \ - NLOHMANN_JSON_PASTE39, \ - NLOHMANN_JSON_PASTE38, \ - NLOHMANN_JSON_PASTE37, \ - NLOHMANN_JSON_PASTE36, \ - NLOHMANN_JSON_PASTE35, \ - NLOHMANN_JSON_PASTE34, \ - NLOHMANN_JSON_PASTE33, \ - NLOHMANN_JSON_PASTE32, \ - NLOHMANN_JSON_PASTE31, \ - NLOHMANN_JSON_PASTE30, \ - NLOHMANN_JSON_PASTE29, \ - NLOHMANN_JSON_PASTE28, \ - NLOHMANN_JSON_PASTE27, \ - NLOHMANN_JSON_PASTE26, \ - NLOHMANN_JSON_PASTE25, \ - NLOHMANN_JSON_PASTE24, \ - NLOHMANN_JSON_PASTE23, \ - NLOHMANN_JSON_PASTE22, \ - NLOHMANN_JSON_PASTE21, \ - NLOHMANN_JSON_PASTE20, \ - NLOHMANN_JSON_PASTE19, \ - NLOHMANN_JSON_PASTE18, \ - NLOHMANN_JSON_PASTE17, \ - NLOHMANN_JSON_PASTE16, \ - NLOHMANN_JSON_PASTE15, \ - NLOHMANN_JSON_PASTE14, \ - NLOHMANN_JSON_PASTE13, \ - NLOHMANN_JSON_PASTE12, \ - NLOHMANN_JSON_PASTE11, \ - NLOHMANN_JSON_PASTE10, \ - NLOHMANN_JSON_PASTE9, \ - NLOHMANN_JSON_PASTE8, \ - NLOHMANN_JSON_PASTE7, \ - NLOHMANN_JSON_PASTE6, \ - NLOHMANN_JSON_PASTE5, \ - NLOHMANN_JSON_PASTE4, \ - NLOHMANN_JSON_PASTE3, \ - NLOHMANN_JSON_PASTE2, \ - NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) -#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) -#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) -#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) -#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) -#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) -#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) -#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) -#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) -#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) -#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) -#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) -#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) -#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) -#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) -#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) -#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) -#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) -#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) -#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) -#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) -#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) -#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) -#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) -#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) -#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) -#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) -#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) -#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) -#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) -#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) -#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) -#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) -#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) -#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) -#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) -#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) -#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) -#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) -#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) -#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) -#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) -#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) -#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) -#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) -#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) -#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) -#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) -#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) -#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) -#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) -#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) -#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) -#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) -#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) -#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) -#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) -#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) -#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) -#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) -#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) -#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) -#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) -#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) - -#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; -#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + AllocatorType, JSONSerializer> /*! -@brief macro -@def NLOHMANN_DEFINE_TYPE_INTRUSIVE -@since version 3.9.0 +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 */ -#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ - friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } -/*! -@brief macro -@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE -@since version 3.9.0 -*/ -#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ - inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ - inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } - -#ifndef JSON_USE_IMPLICIT_CONVERSIONS - #define JSON_USE_IMPLICIT_CONVERSIONS 1 -#endif - -#if JSON_USE_IMPLICIT_CONVERSIONS - #define JSON_EXPLICIT -#else - #define JSON_EXPLICIT explicit -#endif - -#ifndef JSON_DIAGNOSTICS - #define JSON_DIAGNOSTICS 0 -#endif - - -namespace nlohmann -{ -namespace detail -{ - -/*! -@brief replace all occurrences of a substring by another string - -@param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t -@param[in] f the substring to replace with @a t -@param[in] t the string to replace @a f - -@pre The search string @a f must not be empty. **This precondition is -enforced with an assertion.** - -@since version 2.0.0 -*/ -inline void replace_substring(std::string& s, const std::string& f, - const std::string& t) -{ - JSON_ASSERT(!f.empty()); - for (auto pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t, and - pos = s.find(f, pos + t.size())) // find next occurrence of f - {} -} - -/*! - * @brief string escaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to escape - * @return escaped string - * - * Note the order of escaping "~" to "~0" and "/" to "~1" is important. - */ -inline std::string escape(std::string s) -{ - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; -} - -/*! - * @brief string unescaping as described in RFC 6901 (Sect. 4) - * @param[in] s string to unescape - * @return unescaped string - * - * Note the order of escaping "~1" to "/" and "~0" to "~" is important. - */ -static void unescape(std::string& s) -{ - replace_substring(s, "~1", "/"); - replace_substring(s, "~0", "~"); -} - -} // namespace detail -} // namespace nlohmann - -// #include +// #include +#include // not #include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type namespace nlohmann { namespace detail { -/// struct to capture the start position of the current token -struct position_t -{ - /// the total number of characters read - std::size_t chars_read_total = 0; - /// the number of characters read in the current line - std::size_t chars_read_current_line = 0; - /// the number of lines read - std::size_t lines_read = 0; +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; - /// conversion to size_t to preserve SAX interface - constexpr operator size_t() const +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept { - return chars_read_total; + return sizeof...(Ints); } }; -} // namespace detail -} // namespace nlohmann +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} +} + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include // #include +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +// source: https://stackoverflow.com/a/37193089/4116453 + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_string_type_impl : std::false_type {}; + +template +struct is_compatible_string_type_impl +{ + static constexpr auto value = + std::is_same::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_compatible_string_type +{ + static auto constexpr value = is_compatible_string_type_impl < + conjunction>, + has_value_type>::value, + typename BasicJsonType::string_t, CompatibleStringType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +template +struct is_compatible_complete_type +{ + static constexpr bool value = + not std::is_base_of::value and + not is_basic_json::value and + not is_basic_json_nested_type::value and + has_to_json::value; +}; + +template +struct is_compatible_type + : conjunction, + is_compatible_complete_type> +{ +}; +} +} + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + namespace nlohmann { namespace detail @@ -2656,10 +587,9 @@ class exception : public std::exception } /// the id of the exception - const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) + const int id; protected: - JSON_HEDLEY_NON_NULL(3) exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} static std::string name(const std::string& ename, int id_) @@ -2667,70 +597,6 @@ class exception : public std::exception return "[json.exception." + ename + "." + std::to_string(id_) + "] "; } - template - static std::string diagnostics(const BasicJsonType& leaf_element) - { -#if JSON_DIAGNOSTICS - std::vector tokens; - for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent) - { - switch (current->m_parent->type()) - { - case value_t::array: - { - for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) - { - if (¤t->m_parent->m_value.array->operator[](i) == current) - { - tokens.emplace_back(std::to_string(i)); - break; - } - } - break; - } - - case value_t::object: - { - for (const auto& element : *current->m_parent->m_value.object) - { - if (&element.second == current) - { - tokens.emplace_back(element.first.c_str()); - break; - } - } - break; - } - - case value_t::null: // LCOV_EXCL_LINE - case value_t::string: // LCOV_EXCL_LINE - case value_t::boolean: // LCOV_EXCL_LINE - case value_t::number_integer: // LCOV_EXCL_LINE - case value_t::number_unsigned: // LCOV_EXCL_LINE - case value_t::number_float: // LCOV_EXCL_LINE - case value_t::binary: // LCOV_EXCL_LINE - case value_t::discarded: // LCOV_EXCL_LINE - default: // LCOV_EXCL_LINE - break; // LCOV_EXCL_LINE - } - } - - if (tokens.empty()) - { - return ""; - } - - return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + detail::escape(b); - }) + ") "; -#else - static_cast(leaf_element); - return ""; -#endif - } - private: /// an exception object as storage for error messages std::runtime_error m; @@ -2762,8 +628,6 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. -json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). -json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. @note For an input with n bytes, 1 is the index of the first character and n+1 is the index of the terminating null byte or the end of file. This also @@ -2772,12 +636,12 @@ json.exception.parse_error.115 | parse error at byte 5: syntax error while parsi @liveexample{The following code shows how a `parse_error` exception can be caught.,parse_error} -@sa - @ref exception for the base class of the library exceptions -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref type_error for exceptions indicating executing a member function with +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with a wrong type -@sa - @ref out_of_range for exceptions indicating access out of the defined range -@sa - @ref other_error for exceptions indicating other library errors +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ @@ -2787,26 +651,16 @@ class parse_error : public exception /*! @brief create a parse error exception @param[in] id_ the id of the exception - @param[in] pos the position where the error occurred (or with - chars_read_total=0 if the position cannot be - determined) + @param[in] byte_ the byte index where the error occurred (or 0 if the + position cannot be determined) @param[in] what_arg the explanatory string @return parse_error object */ - template - static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context) + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) { std::string w = exception::name("parse_error", id_) + "parse error" + - position_string(pos) + ": " + exception::diagnostics(context) + what_arg; - return parse_error(id_, pos.chars_read_total, w.c_str()); - } - - template - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + - ": " + exception::diagnostics(context) + what_arg; + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + + ": " + what_arg; return parse_error(id_, byte_, w.c_str()); } @@ -2824,12 +678,6 @@ class parse_error : public exception private: parse_error(int id_, std::size_t byte_, const char* what_arg) : exception(id_, what_arg), byte(byte_) {} - - static std::string position_string(const position_t& pos) - { - return " at line " + std::to_string(pos.lines_read + 1) + - ", column " + std::to_string(pos.chars_read_current_line); - } }; /*! @@ -2860,27 +708,25 @@ json.exception.invalid_iterator.214 | cannot get value | Cannot get value for it @liveexample{The following code shows how an `invalid_iterator` exception can be caught.,invalid_iterator} -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref type_error for exceptions indicating executing a member function with +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with a wrong type -@sa - @ref out_of_range for exceptions indicating access out of the defined range -@sa - @ref other_error for exceptions indicating other library errors +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class invalid_iterator : public exception { public: - template - static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context) + static invalid_iterator create(int id_, const std::string& what_arg) { - std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("invalid_iterator", id_) + what_arg; return invalid_iterator(id_, w.c_str()); } private: - JSON_HEDLEY_NON_NULL(3) invalid_iterator(int id_, const char* what_arg) : exception(id_, what_arg) {} }; @@ -2897,7 +743,7 @@ name / id | example message | description ----------------------------- | --------------- | ------------------------- json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. @@ -2911,31 +757,28 @@ json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | -json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | @liveexample{The following code shows how a `type_error` exception can be caught.,type_error} -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref out_of_range for exceptions indicating access out of the defined range -@sa - @ref other_error for exceptions indicating other library errors +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class type_error : public exception { public: - template - static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context) + static type_error create(int id_, const std::string& what_arg) { - std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("type_error", id_) + what_arg; return type_error(id_, w.c_str()); } private: - JSON_HEDLEY_NON_NULL(3) type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; @@ -2956,34 +799,31 @@ json.exception.out_of_range.403 | key 'foo' not found | The provided key was not json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. -json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | -json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | @liveexample{The following code shows how an `out_of_range` exception can be caught.,out_of_range} -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref type_error for exceptions indicating executing a member function with +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with a wrong type -@sa - @ref other_error for exceptions indicating other library errors +@sa @ref other_error for exceptions indicating other library errors @since version 3.0.0 */ class out_of_range : public exception { public: - template - static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context) + static out_of_range create(int id_, const std::string& what_arg) { - std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("out_of_range", id_) + what_arg; return out_of_range(id_, w.c_str()); } private: - JSON_HEDLEY_NON_NULL(3) out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} }; @@ -2999,12 +839,12 @@ name / id | example message | description ------------------------------ | --------------- | ------------------------- json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. -@sa - @ref exception for the base class of the library exceptions -@sa - @ref parse_error for exceptions indicating a parse error -@sa - @ref invalid_iterator for exceptions indicating errors with iterators -@sa - @ref type_error for exceptions indicating executing a member function with +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with a wrong type -@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref out_of_range for exceptions indicating access out of the defined range @liveexample{The following code shows how an `other_error` exception can be caught.,other_error} @@ -3014,874 +854,119 @@ caught.,other_error} class other_error : public exception { public: - template - static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context) + static other_error create(int id_, const std::string& what_arg) { - std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg; + std::string w = exception::name("other_error", id_) + what_arg; return other_error(id_, w.c_str()); } private: - JSON_HEDLEY_NON_NULL(3) other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} }; -} // namespace detail -} // namespace nlohmann +} +} -// #include - -// #include +// #include +#include // array +#include // and #include // size_t -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type -#include // index_sequence, make_index_sequence, index_sequence_for - -// #include - +#include // uint8_t namespace nlohmann { namespace detail { - -template -using uncvref_t = typename std::remove_cv::type>::type; - -#ifdef JSON_HAS_CPP_14 - -// the following utilities are natively available in C++14 -using std::enable_if_t; -using std::index_sequence; -using std::make_index_sequence; -using std::index_sequence_for; - -#else - -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h -// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. - -//// START OF CODE FROM GOOGLE ABSEIL - -// integer_sequence -// -// Class template representing a compile-time integer sequence. An instantiation -// of `integer_sequence` has a sequence of integers encoded in its -// type through its template arguments (which is a common need when -// working with C++11 variadic templates). `absl::integer_sequence` is designed -// to be a drop-in replacement for C++14's `std::integer_sequence`. -// -// Example: -// -// template< class T, T... Ints > -// void user_function(integer_sequence); -// -// int main() -// { -// // user_function's `T` will be deduced to `int` and `Ints...` -// // will be deduced to `0, 1, 2, 3, 4`. -// user_function(make_integer_sequence()); -// } -template -struct integer_sequence -{ - using value_type = T; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -// index_sequence -// -// A helper template for an `integer_sequence` of `size_t`, -// `absl::index_sequence` is designed to be a drop-in replacement for C++14's -// `std::index_sequence`. -template -using index_sequence = integer_sequence; - -namespace utility_internal -{ - -template -struct Extend; - -// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. -template -struct Extend, SeqSize, 0> -{ - using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; -}; - -template -struct Extend, SeqSize, 1> -{ - using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; -}; - -// Recursion helper for 'make_integer_sequence'. -// 'Gen::type' is an alias for 'integer_sequence'. -template -struct Gen -{ - using type = - typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; -}; - -template -struct Gen -{ - using type = integer_sequence; -}; - -} // namespace utility_internal - -// Compile-time sequences of integers - -// make_integer_sequence -// -// This template alias is equivalent to -// `integer_sequence`, and is designed to be a drop-in -// replacement for C++14's `std::make_integer_sequence`. -template -using make_integer_sequence = typename utility_internal::Gen::type; - -// make_index_sequence -// -// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, -// and is designed to be a drop-in replacement for C++14's -// `std::make_index_sequence`. -template -using make_index_sequence = make_integer_sequence; - -// index_sequence_for -// -// Converts a typename pack into an index sequence of the same length, and -// is designed to be a drop-in replacement for C++14's -// `std::index_sequence_for()` -template -using index_sequence_for = make_index_sequence; - -//// END OF CODE FROM GOOGLE ABSEIL - -#endif - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; - -} // namespace detail -} // namespace nlohmann - -// #include - - -namespace nlohmann -{ -namespace detail -{ -// dispatching helper struct -template struct identity_tag {}; -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // numeric_limits -#include // false_type, is_constructible, is_integral, is_same, true_type -#include // declval -#include // tuple - -// #include - - -#include // random_access_iterator_tag - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template struct make_void -{ - using type = void; -}; -template using void_t = typename make_void::type; -} // namespace detail -} // namespace nlohmann - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -struct iterator_types {}; - -template -struct iterator_types < - It, - void_t> -{ - using difference_type = typename It::difference_type; - using value_type = typename It::value_type; - using pointer = typename It::pointer; - using reference = typename It::reference; - using iterator_category = typename It::iterator_category; -}; - -// This is required as some compilers implement std::iterator_traits in a way that -// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. -template -struct iterator_traits -{ -}; - -template -struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> - : iterator_types -{ -}; - -template -struct iterator_traits::value>> -{ - using iterator_category = std::random_access_iterator_tag; - using value_type = T; - using difference_type = ptrdiff_t; - using pointer = T*; - using reference = T&; -}; -} // namespace detail -} // namespace nlohmann - -// #include - -// #include - -// #include - - -#include - -// #include - - -// https://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - nonesuch(nonesuch const&&) = delete; - void operator=(nonesuch const&) = delete; - void operator=(nonesuch&&) = delete; -}; - -template class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template class Op, class... Args> -struct detector>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op; -}; - -template class Op, class... Args> -using is_detected = typename detector::value_t; - -template class Op, class... Args> -struct is_detected_lazy : is_detected { }; - -template class Op, class... Args> -using detected_t = typename detector::type; - -template class Op, class... Args> -using detected_or = detector; - -template class Op, class... Args> -using detected_or_t = typename detected_or::type; - -template class Op, class... Args> -using is_detected_exact = std::is_same>; - -template class Op, class... Args> -using is_detected_convertible = - std::is_convertible, To>; -} // namespace detail -} // namespace nlohmann - -// #include -#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ -#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector +/////////////////////////// +// JSON type enumeration // +/////////////////////////// /*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument +@brief the JSON type enumeration -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer, - class BinaryType = std::vector> -class basic_json; +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -template -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type @since version 1.0.0 */ -using json = basic_json<>; - -template -struct ordered_map; +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; /*! -@brief ordered JSON class +@brief comparison operator for JSON types -This type preserves the insertion order of object keys. +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself +- discarded values are not comparable -@since version 3.9.0 +@since version 1.0.0 */ -using ordered_json = basic_json; - -} // namespace nlohmann - -#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ - - -namespace nlohmann +inline bool operator<(const value_t lhs, const value_t rhs) noexcept { -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -// Note to maintainers: -// -// Every trait in this file expects a non CV-qualified type. -// The only exceptions are in the 'aliases for detected' section -// (i.e. those of the form: decltype(T::member_function(std::declval()))) -// -// In this case, T has to be properly CV-qualified to constraint the function arguments -// (e.g. to_json(BasicJsonType&, const T&)) - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -////////////////////// -// json_ref helpers // -////////////////////// - -template -class json_ref; - -template -struct is_json_ref : std::false_type {}; - -template -struct is_json_ref> : std::true_type {}; - -////////////////////////// -// aliases for detected // -////////////////////////// - -template -using mapped_type_t = typename T::mapped_type; - -template -using key_type_t = typename T::key_type; - -template -using value_type_t = typename T::value_type; - -template -using difference_type_t = typename T::difference_type; - -template -using pointer_t = typename T::pointer; - -template -using reference_t = typename T::reference; - -template -using iterator_category_t = typename T::iterator_category; - -template -using iterator_t = typename T::iterator; - -template -using to_json_function = decltype(T::to_json(std::declval()...)); - -template -using from_json_function = decltype(T::from_json(std::declval()...)); - -template -using get_template_function = decltype(std::declval().template get()); - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json : std::false_type {}; - -// trait checking if j.get is valid -// use this trait instead of std::is_constructible or std::is_convertible, -// both rely on, or make use of implicit conversions, and thus fail when T -// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) -template -struct is_getable -{ - static constexpr bool value = is_detected::value; -}; - -template -struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> -{ - using serializer = typename BasicJsonType::template json_serializer; - - static constexpr bool value = - is_detected_exact::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json : std::false_type {}; - -template -struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> -{ - using serializer = typename BasicJsonType::template json_serializer; - - static constexpr bool value = - is_detected_exact::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. -template -struct has_to_json : std::false_type {}; - -template -struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> -{ - using serializer = typename BasicJsonType::template json_serializer; - - static constexpr bool value = - is_detected_exact::value; -}; - - -/////////////////// -// is_ functions // -/////////////////// - -// https://en.cppreference.com/w/cpp/types/conjunction -template struct conjunction : std::true_type { }; -template struct conjunction : B1 { }; -template -struct conjunction -: std::conditional, B1>::type {}; - -// https://en.cppreference.com/w/cpp/types/negation -template struct negation : std::integral_constant < bool, !B::value > { }; - -// Reimplementation of is_constructible and is_default_constructible, due to them being broken for -// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). -// This causes compile errors in e.g. clang 3.5 or gcc 4.9. -template -struct is_default_constructible : std::is_default_constructible {}; - -template -struct is_default_constructible> - : conjunction, is_default_constructible> {}; - -template -struct is_default_constructible> - : conjunction, is_default_constructible> {}; - -template -struct is_default_constructible> - : conjunction...> {}; - -template -struct is_default_constructible> - : conjunction...> {}; - - -template -struct is_constructible : std::is_constructible {}; - -template -struct is_constructible> : is_default_constructible> {}; - -template -struct is_constructible> : is_default_constructible> {}; - -template -struct is_constructible> : is_default_constructible> {}; - -template -struct is_constructible> : is_default_constructible> {}; - - -template -struct is_iterator_traits : std::false_type {}; - -template -struct is_iterator_traits> -{ - private: - using traits = iterator_traits; - - public: - static constexpr auto value = - is_detected::value && - is_detected::value && - is_detected::value && - is_detected::value && - is_detected::value; -}; - -// The following implementation of is_complete_type is taken from -// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ -// and is written by Xiang Fan who agreed to using it in this library. - -template -struct is_complete_type : std::false_type {}; - -template -struct is_complete_type : std::true_type {}; - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl < - BasicJsonType, CompatibleObjectType, - enable_if_t < is_detected::value&& - is_detected::value >> -{ - using object_t = typename BasicJsonType::object_t; - - // macOS's is_constructible does not play well with nonesuch... - static constexpr bool value = - is_constructible::value && - is_constructible::value; -}; - -template -struct is_compatible_object_type - : is_compatible_object_type_impl {}; - -template -struct is_constructible_object_type_impl : std::false_type {}; - -template -struct is_constructible_object_type_impl < - BasicJsonType, ConstructibleObjectType, - enable_if_t < is_detected::value&& - is_detected::value >> -{ - using object_t = typename BasicJsonType::object_t; - - static constexpr bool value = - (is_default_constructible::value && - (std::is_move_assignable::value || - std::is_copy_assignable::value) && - (is_constructible::value && - std::is_same < - typename object_t::mapped_type, - typename ConstructibleObjectType::mapped_type >::value)) || - (has_from_json::value || - has_non_default_from_json < - BasicJsonType, - typename ConstructibleObjectType::mapped_type >::value); -}; - -template -struct is_constructible_object_type - : is_constructible_object_type_impl {}; - -template -struct is_compatible_string_type_impl : std::false_type {}; - -template -struct is_compatible_string_type_impl < - BasicJsonType, CompatibleStringType, - enable_if_t::value >> -{ - static constexpr auto value = - is_constructible::value; -}; - -template -struct is_compatible_string_type - : is_compatible_string_type_impl {}; - -template -struct is_constructible_string_type_impl : std::false_type {}; - -template -struct is_constructible_string_type_impl < - BasicJsonType, ConstructibleStringType, - enable_if_t::value >> -{ - static constexpr auto value = - is_constructible::value; -}; - -template -struct is_constructible_string_type - : is_constructible_string_type_impl {}; - -template -struct is_compatible_array_type_impl : std::false_type {}; - -template -struct is_compatible_array_type_impl < - BasicJsonType, CompatibleArrayType, - enable_if_t < is_detected::value&& - is_detected::value&& -// This is needed because json_reverse_iterator has a ::iterator type... -// Therefore it is detected as a CompatibleArrayType. -// The real fix would be to have an Iterable concept. - !is_iterator_traits < - iterator_traits>::value >> -{ - static constexpr bool value = - is_constructible::value; -}; - -template -struct is_compatible_array_type - : is_compatible_array_type_impl {}; - -template -struct is_constructible_array_type_impl : std::false_type {}; - -template -struct is_constructible_array_type_impl < - BasicJsonType, ConstructibleArrayType, - enable_if_t::value >> - : std::true_type {}; - -template -struct is_constructible_array_type_impl < - BasicJsonType, ConstructibleArrayType, - enable_if_t < !std::is_same::value&& - is_default_constructible::value&& -(std::is_move_assignable::value || - std::is_copy_assignable::value)&& -is_detected::value&& -is_detected::value&& -is_complete_type < -detected_t>::value >> -{ - static constexpr bool value = - // This is needed because json_reverse_iterator has a ::iterator type, - // furthermore, std::back_insert_iterator (and other iterators) have a - // base class `iterator`... Therefore it is detected as a - // ConstructibleArrayType. The real fix would be to have an Iterable - // concept. - !is_iterator_traits>::value && - - (std::is_same::value || - has_from_json::value || - has_non_default_from_json < - BasicJsonType, typename ConstructibleArrayType::value_type >::value); -}; - -template -struct is_constructible_array_type - : is_constructible_array_type_impl {}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl < - RealIntegerType, CompatibleNumberIntegerType, - enable_if_t < std::is_integral::value&& - std::is_integral::value&& - !std::is_same::value >> -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - is_constructible::value && - CompatibleLimits::is_integer && - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type - : is_compatible_integer_type_impl {}; - -template -struct is_compatible_type_impl: std::false_type {}; - -template -struct is_compatible_type_impl < - BasicJsonType, CompatibleType, - enable_if_t::value >> -{ - static constexpr bool value = - has_to_json::value; -}; - -template -struct is_compatible_type - : is_compatible_type_impl {}; - -template -struct is_constructible_tuple : std::false_type {}; - -template -struct is_constructible_tuple> : conjunction...> {}; - -// a naive helper to check if a type is an ordered_map (exploits the fact that -// ordered_map inherits capacity() from std::vector) -template -struct is_ordered_map -{ - using one = char; - - struct two - { - char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } }; - template static one test( decltype(&C::capacity) ) ; - template static two test(...); - - enum { value = sizeof(test(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) -}; - -// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) -template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > -T conditional_static_cast(U value) -{ - return static_cast(value); + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; +} +} } -template::value, int> = 0> -T conditional_static_cast(U value) -{ - return value; -} +// #include -} // namespace detail -} // namespace nlohmann + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + +// #include + +// #include + +// #include // #include @@ -3893,18 +978,18 @@ namespace detail template void from_json(const BasicJsonType& j, typename std::nullptr_t& n) { - if (JSON_HEDLEY_UNLIKELY(!j.is_null())) + if (JSON_UNLIKELY(not j.is_null())) { - JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); } n = nullptr; } // overloads for basic_json template parameters -template < typename BasicJsonType, typename ArithmeticType, - enable_if_t < std::is_arithmetic::value&& - !std::is_same::value, - int > = 0 > +template::value and + not std::is_same::value, + int> = 0> void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) { switch (static_cast(j)) @@ -3925,24 +1010,17 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) break; } - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::string: - case value_t::boolean: - case value_t::binary: - case value_t::discarded: default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); } } template void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) { - if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) + if (JSON_UNLIKELY(not j.is_boolean())) { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); } b = *j.template get_ptr(); } @@ -3950,25 +1028,25 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) template void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) { - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + if (JSON_UNLIKELY(not j.is_string())) { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); } s = *j.template get_ptr(); } template < - typename BasicJsonType, typename ConstructibleStringType, + typename BasicJsonType, typename CompatibleStringType, enable_if_t < - is_constructible_string_type::value&& - !std::is_same::value, + is_compatible_string_type::value and + not std::is_same::value, int > = 0 > -void from_json(const BasicJsonType& j, ConstructibleStringType& s) +void from_json(const BasicJsonType& j, CompatibleStringType& s) { - if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + if (JSON_UNLIKELY(not j.is_string())) { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); } s = *j.template get_ptr(); @@ -4001,16 +1079,25 @@ void from_json(const BasicJsonType& j, EnumType& e) e = static_cast(val); } +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + arr = *j.template get_ptr(); +} + // forward_list doesn't have an insert method template::value, int> = 0> + enable_if_t::value, int> = 0> void from_json(const BasicJsonType& j, std::forward_list& l) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + if (JSON_UNLIKELY(not j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } - l.clear(); std::transform(j.rbegin(), j.rend(), std::front_inserter(l), [](const BasicJsonType & i) { @@ -4020,178 +1107,110 @@ void from_json(const BasicJsonType& j, std::forward_list& l) // valarray doesn't have an insert method template::value, int> = 0> + enable_if_t::value, int> = 0> void from_json(const BasicJsonType& j, std::valarray& l) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + if (JSON_UNLIKELY(not j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } l.resize(j.size()); - std::transform(j.begin(), j.end(), std::begin(l), - [](const BasicJsonType & elem) + std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +{ + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) { - return elem.template get(); + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); }); } -template -auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) --> decltype(j.template get(), void()) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template -void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) -{ - arr = *j.template get_ptr(); -} - -template -auto from_json_array_impl(const BasicJsonType& j, std::array& arr, - priority_tag<2> /*unused*/) --> decltype(j.template get(), void()) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template::value, - int> = 0> -auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( - arr.reserve(std::declval()), - j.template get(), + arr.reserve(std::declval()), void()) { using std::end; - ConstructibleArrayType ret; - ret.reserve(j.size()); + arr.reserve(j.size()); std::transform(j.begin(), j.end(), - std::inserter(ret, end(ret)), [](const BasicJsonType & i) + std::inserter(arr, end(arr)), [](const BasicJsonType & i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType - return i.template get(); + return i.template get(); }); - arr = std::move(ret); } -template::value, - int> = 0> -void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, - priority_tag<0> /*unused*/) +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) { - using std::end; - - ConstructibleArrayType ret; - std::transform( - j.begin(), j.end(), std::inserter(ret, end(ret)), - [](const BasicJsonType & i) + for (std::size_t i = 0; i < N; ++i) { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); - arr = std::move(ret); + arr[i] = j.at(i).template get(); + } } -template < typename BasicJsonType, typename ConstructibleArrayType, - enable_if_t < - is_constructible_array_type::value&& - !is_constructible_object_type::value&& - !is_constructible_string_type::value&& - !std::is_same::value&& - !is_basic_json::value, - int > = 0 > -auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) --> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), -j.template get(), -void()) +template < + typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type::value and + not std::is_same::value and + std::is_constructible < + BasicJsonType, typename CompatibleArrayType::value_type >::value, + int > = 0 > +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + if (JSON_UNLIKELY(not j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + + std::string(j.type_name()))); } - from_json_array_impl(j, arr, priority_tag<3> {}); + from_json_array_impl(j, arr, priority_tag<2> {}); } -template < typename BasicJsonType, typename T, std::size_t... Idx > -std::array from_json_inplace_array_impl(BasicJsonType&& j, - identity_tag> /*unused*/, index_sequence /*unused*/) +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) { - return { { std::forward(j).at(Idx).template get()... } }; -} - -template < typename BasicJsonType, typename T, std::size_t N > -auto from_json(BasicJsonType&& j, identity_tag> tag) --> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + if (JSON_UNLIKELY(not j.is_object())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); } - return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) - { - JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()), j)); - } - - bin = *j.template get_ptr(); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_object())) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()), j)); - } - - ConstructibleObjectType ret; - const auto* inner_object = j.template get_ptr(); - using value_type = typename ConstructibleObjectType::value_type; + auto inner_object = j.template get_ptr(); + using value_type = typename CompatibleObjectType::value_type; std::transform( inner_object->begin(), inner_object->end(), - std::inserter(ret, ret.begin()), + std::inserter(obj, obj.begin()), [](typename BasicJsonType::object_t::value_type const & p) { - return value_type(p.first, p.second.template get()); + return value_type(p.first, p.second.template get()); }); - obj = std::move(ret); } // overload for arithmetic types, not chosen for basic_json template arguments // (BooleanType, etc..); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? -template < typename BasicJsonType, typename ArithmeticType, - enable_if_t < - std::is_arithmetic::value&& - !std::is_same::value&& - !std::is_same::value&& - !std::is_same::value&& - !std::is_same::value, - int > = 0 > +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> void from_json(const BasicJsonType& j, ArithmeticType& val) { switch (static_cast(j)) @@ -4217,95 +1236,62 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) break; } - case value_t::null: - case value_t::object: - case value_t::array: - case value_t::string: - case value_t::binary: - case value_t::discarded: default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); } } -template -std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) -{ - return std::make_tuple(std::forward(j).at(Idx).template get()...); -} - -template < typename BasicJsonType, class A1, class A2 > -std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) -{ - return {std::forward(j).at(0).template get(), - std::forward(j).at(1).template get()}; -} - template -void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) +void from_json(const BasicJsonType& j, std::pair& p) { - p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); + p = {j.at(0).template get(), j.at(1).template get()}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx).template get::type>()...); } template -std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) +void from_json(const BasicJsonType& j, std::tuple& t) { - return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); + from_json_tuple_impl(j, t, index_sequence_for {}); } -template -void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) -{ - t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); -} - -template -auto from_json(BasicJsonType&& j, TupleRelated&& t) --> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) -{ - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); - } - - return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); -} - -template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> +template ::value>> void from_json(const BasicJsonType& j, std::map& m) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + if (JSON_UNLIKELY(not j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } - m.clear(); for (const auto& p : j) { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + if (JSON_UNLIKELY(not p.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); } m.emplace(p.at(0).template get(), p.at(1).template get()); } } -template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> +template ::value>> void from_json(const BasicJsonType& j, std::unordered_map& m) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + if (JSON_UNLIKELY(not j.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); } - m.clear(); for (const auto& p : j) { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + if (JSON_UNLIKELY(not p.is_array())) { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); } m.emplace(p.at(0).template get(), p.at(1).template get()); } @@ -4313,47 +1299,70 @@ void from_json(const BasicJsonType& j, std::unordered_map - auto operator()(const BasicJsonType& j, T&& val) const - noexcept(noexcept(from_json(j, std::forward(val)))) - -> decltype(from_json(j, std::forward(val))) + auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) { - return from_json(j, std::forward(val)); + return from_json(j, val); + } + + template + void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); } }; -} // namespace detail +} /// namespace to hold default `from_json` function /// to see why this is required: /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +namespace { -constexpr const auto& from_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) -} // namespace -} // namespace nlohmann +constexpr const auto& from_json = detail::static_const::value; +} +} // #include -#include // copy +#include // or, and, not #include // begin, end -#include // string #include // tuple, get #include // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include // move, forward, declval, pair #include // valarray #include // vector +// #include + +// #include + +// #include + // #include #include // size_t -#include // input_iterator_tag #include // string, to_string -#include // tuple_size, get, tuple_element -#include // move - -// #include +#include // input_iterator_tag // #include @@ -4362,114 +1371,100 @@ namespace nlohmann { namespace detail { -template -void int_to_string( string_type& target, std::size_t value ) -{ - // For ADL - using std::to_string; - target = to_string(value); -} -template class iteration_proxy_value -{ - public: - using difference_type = std::ptrdiff_t; - using value_type = iteration_proxy_value; - using pointer = value_type * ; - using reference = value_type & ; - using iterator_category = std::input_iterator_tag; - using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; - - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - /// last stringified array index - mutable std::size_t array_index_last = 0; - /// a string representation of the array index - mutable string_type array_index_str = "0"; - /// an empty string (to return a reference for primitive values) - const string_type empty_str{}; - - public: - explicit iteration_proxy_value(IteratorType it) noexcept - : anchor(std::move(it)) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_value& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_value& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// equality operator (needed for InputIterator) - bool operator==(const iteration_proxy_value& o) const - { - return anchor == o.anchor; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_value& o) const - { - return anchor != o.anchor; - } - - /// return key of the iterator - const string_type& key() const - { - JSON_ASSERT(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - if (array_index != array_index_last) - { - int_to_string( array_index_str, array_index ); - array_index_last = array_index; - } - return array_index_str; - } - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return empty_str; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } -}; - /// proxy class for the items() function template class iteration_proxy { private: + /// helper class for iteration + class iteration_proxy_internal + { + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_internal; + using pointer = iteration_proxy_internal*; + using reference = iteration_proxy_internal&; + using iterator_category = std::input_iterator_tag; + + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable std::string array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + const std::string empty_str = ""; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} + + iteration_proxy_internal(const iteration_proxy_internal&) = default; + iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default; + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_internal& o) const noexcept + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal& o) const noexcept + { + return anchor != o.anchor; + } + + /// return key of the iterator + const std::string& key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + array_index_str = std::to_string(array_index); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + /// the container to iterate typename IteratorType::reference container; @@ -4479,69 +1474,19 @@ template class iteration_proxy : container(cont) {} /// return iterator begin (needed for range-based for) - iteration_proxy_value begin() noexcept + iteration_proxy_internal begin() noexcept { - return iteration_proxy_value(container.begin()); + return iteration_proxy_internal(container.begin()); } /// return iterator end (needed for range-based for) - iteration_proxy_value end() noexcept + iteration_proxy_internal end() noexcept { - return iteration_proxy_value(container.end()); + return iteration_proxy_internal(container.end()); } }; -// Structured Bindings Support -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -template = 0> -auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) -{ - return i.key(); } -// Structured Bindings Support -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -template = 0> -auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) -{ - return i.value(); } -} // namespace detail -} // namespace nlohmann - -// The Addition to the STD Namespace is required to add -// Structured Bindings Support to the iteration_proxy_value class -// For further reference see https://blog.tartanllama.xyz/structured-bindings/ -// And see https://github.com/nlohmann/json/pull/1391 -namespace std -{ -#if defined(__clang__) - // Fix: https://github.com/nlohmann/json/issues/1401 - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wmismatched-tags" -#endif -template -class tuple_size<::nlohmann::detail::iteration_proxy_value> - : public std::integral_constant {}; - -template -class tuple_element> -{ - public: - using type = decltype( - get(std::declval < - ::nlohmann::detail::iteration_proxy_value> ())); -}; -#if defined(__clang__) - #pragma clang diagnostic pop -#endif -} // namespace std - -// #include - -// #include - -// #include namespace nlohmann @@ -4552,13 +1497,6 @@ namespace detail // constructors // ////////////////// -/* - * Note all external_constructor<>::construct functions need to call - * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an - * allocated value (e.g., a string). See bug issue - * https://github.com/nlohmann/json/issues/2865 for more information. - */ - template struct external_constructor; template<> @@ -4567,7 +1505,6 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept { - j.m_value.destroy(j.m_type); j.m_type = value_t::boolean; j.m_value = b; j.assert_invariant(); @@ -4580,7 +1517,6 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) { - j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value = s; j.assert_invariant(); @@ -4589,53 +1525,28 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) { - j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value = std::move(s); j.assert_invariant(); } - template < typename BasicJsonType, typename CompatibleStringType, - enable_if_t < !std::is_same::value, - int > = 0 > + template::value, + int> = 0> static void construct(BasicJsonType& j, const CompatibleStringType& str) { - j.m_value.destroy(j.m_type); j.m_type = value_t::string; j.m_value.string = j.template create(str); j.assert_invariant(); } }; -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::binary; - j.m_value = typename BasicJsonType::binary_t(b); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) - { - j.m_value.destroy(j.m_type); - j.m_type = value_t::binary; - j.m_value = typename BasicJsonType::binary_t(std::move(b)); - j.assert_invariant(); - } -}; - template<> struct external_constructor { template static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept { - j.m_value.destroy(j.m_type); j.m_type = value_t::number_float; j.m_value = val; j.assert_invariant(); @@ -4648,7 +1559,6 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept { - j.m_value.destroy(j.m_type); j.m_type = value_t::number_unsigned; j.m_value = val; j.assert_invariant(); @@ -4661,7 +1571,6 @@ struct external_constructor template static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept { - j.m_value.destroy(j.m_type); j.m_type = value_t::number_integer; j.m_value = val; j.assert_invariant(); @@ -4674,49 +1583,40 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) { - j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = arr; - j.set_parents(); j.assert_invariant(); } template static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) { - j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = std::move(arr); - j.set_parents(); j.assert_invariant(); } - template < typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < !std::is_same::value, - int > = 0 > + template::value, + int> = 0> static void construct(BasicJsonType& j, const CompatibleArrayType& arr) { using std::begin; using std::end; - - j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value.array = j.template create(begin(arr), end(arr)); - j.set_parents(); j.assert_invariant(); } template static void construct(BasicJsonType& j, const std::vector& arr) { - j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->reserve(arr.size()); for (const bool x : arr) { j.m_value.array->push_back(x); - j.set_parent(j.m_value.array->back()); } j.assert_invariant(); } @@ -4725,15 +1625,10 @@ struct external_constructor enable_if_t::value, int> = 0> static void construct(BasicJsonType& j, const std::valarray& arr) { - j.m_value.destroy(j.m_type); j.m_type = value_t::array; j.m_value = value_t::array; j.m_value.array->resize(arr.size()); - if (arr.size() > 0) - { - std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); - } - j.set_parents(); + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); j.assert_invariant(); } }; @@ -4744,34 +1639,28 @@ struct external_constructor template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { - j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value = obj; - j.set_parents(); j.assert_invariant(); } template static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) { - j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value = std::move(obj); - j.set_parents(); j.assert_invariant(); } - template < typename BasicJsonType, typename CompatibleObjectType, - enable_if_t < !std::is_same::value, int > = 0 > + template::value, int> = 0> static void construct(BasicJsonType& j, const CompatibleObjectType& obj) { using std::begin; using std::end; - j.m_value.destroy(j.m_type); j.m_type = value_t::object; j.m_value.object = j.template create(begin(obj), end(obj)); - j.set_parents(); j.assert_invariant(); } }; @@ -4835,25 +1724,15 @@ void to_json(BasicJsonType& j, const std::vector& e) external_constructor::construct(j, e); } -template < typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < is_compatible_array_type::value&& - !is_compatible_object_type::value&& - !is_compatible_string_type::value&& - !std::is_same::value&& - !is_basic_json::value, - int > = 0 > +template::value or + std::is_same::value, + int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor::construct(j, arr); } -template -void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) -{ - external_constructor::construct(j, bin); -} - template::value, int> = 0> void to_json(BasicJsonType& j, const std::valarray& arr) @@ -4867,8 +1746,8 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) external_constructor::construct(j, std::move(arr)); } -template < typename BasicJsonType, typename CompatibleObjectType, - enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > +template::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleObjectType& obj) { external_constructor::construct(j, obj); @@ -4880,458 +1759,87 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) external_constructor::construct(j, std::move(obj)); } -template < - typename BasicJsonType, typename T, std::size_t N, - enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - int > = 0 > -void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +template::value, int> = 0> +void to_json(BasicJsonType& j, T (&arr)[N]) { external_constructor::construct(j, arr); } -template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > -void to_json(BasicJsonType& j, const std::pair& p) +template +void to_json(BasicJsonType& j, const std::pair& p) { - j = { p.first, p.second }; + j = {p.first, p.second}; } // for https://github.com/nlohmann/json/pull/1134 template>::value, int> = 0> -void to_json(BasicJsonType& j, const T& b) + enable_if_t::iteration_proxy_internal>::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept { - j = { {b.key(), b.value()} }; + j = {{b.key(), b.value()}}; } template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) { - j = { std::get(t)... }; + j = {std::get(t)...}; } -template::value, int > = 0> -void to_json(BasicJsonType& j, const T& t) +template +void to_json(BasicJsonType& j, const std::tuple& t) { - to_json_tuple_impl(j, t, make_index_sequence::value> {}); + to_json_tuple_impl(j, t, index_sequence_for {}); } struct to_json_fn { + private: template - auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) + auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) -> decltype(to_json(j, std::forward(val)), void()) { return to_json(j, std::forward(val)); } + + template + void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + +#ifdef _MSC_VER + // MSVC does not show a stacktrace for the above assert + using decayed = uncvref_t; + static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, + "forcing MSVC stacktrace to show which T we're talking about."); +#endif + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } }; -} // namespace detail +} /// namespace to hold default `to_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +namespace { -constexpr const auto& to_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) -} // namespace -} // namespace nlohmann - -// #include - -// #include - - -namespace nlohmann -{ - -template -struct adl_serializer -{ - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @note This function is chosen for default-constructible value types. - - @param[in] j JSON value to read from - @param[in,out] val value to write to - */ - template - static auto from_json(BasicJsonType && j, TargetType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), val))) - -> decltype(::nlohmann::from_json(std::forward(j), val), void()) - { - ::nlohmann::from_json(std::forward(j), val); - } - - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @note This function is chosen for value types which are not default-constructible. - - @param[in] j JSON value to read from - - @return copy of the JSON value, converted to @a ValueType - */ - template - static auto from_json(BasicJsonType && j) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) - -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) - { - return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); - } - - /*! - @brief convert any value type to a JSON value - - This function is usually called by the constructors of the @ref basic_json - class. - - @param[in,out] j JSON value to write to - @param[in] val value to read from - */ - template - static auto to_json(BasicJsonType& j, TargetType && val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) - { - ::nlohmann::to_json(j, std::forward(val)); - } -}; -} // namespace nlohmann - -// #include - - -#include // uint8_t, uint64_t -#include // tie -#include // move - -namespace nlohmann -{ - -/*! -@brief an internal type for a backed binary type - -This type extends the template parameter @a BinaryType provided to `basic_json` -with a subtype used by BSON and MessagePack. This type exists so that the user -does not have to specify a type themselves with a specific naming scheme in -order to override the binary type. - -@tparam BinaryType container to store bytes (`std::vector` by - default) - -@since version 3.8.0; changed type of subtypes to std::uint64_t in 3.10.0. -*/ -template -class byte_container_with_subtype : public BinaryType -{ - public: - /// the type of the underlying container - using container_type = BinaryType; - /// the type of the subtype - using subtype_type = std::uint64_t; - - byte_container_with_subtype() noexcept(noexcept(container_type())) - : container_type() - {} - - byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) - : container_type(b) - {} - - byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - {} - - byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) - : container_type(b) - , m_subtype(subtype_) - , m_has_subtype(true) - {} - - byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) - : container_type(std::move(b)) - , m_subtype(subtype_) - , m_has_subtype(true) - {} - - bool operator==(const byte_container_with_subtype& rhs) const - { - return std::tie(static_cast(*this), m_subtype, m_has_subtype) == - std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); - } - - bool operator!=(const byte_container_with_subtype& rhs) const - { - return !(rhs == *this); - } - - /*! - @brief sets the binary subtype - - Sets the binary subtype of the value, also flags a binary JSON value as - having a subtype, which has implications for serialization. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa see @ref subtype() -- return the binary subtype - @sa see @ref clear_subtype() -- clears the binary subtype - @sa see @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - void set_subtype(subtype_type subtype_) noexcept - { - m_subtype = subtype_; - m_has_subtype = true; - } - - /*! - @brief return the binary subtype - - Returns the numerical subtype of the value if it has a subtype. If it does - not have a subtype, this function will return subtype_type(-1) as a sentinel - value. - - @return the numerical subtype of the binary value - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa see @ref set_subtype() -- sets the binary subtype - @sa see @ref clear_subtype() -- clears the binary subtype - @sa see @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0; fixed return value to properly return - subtype_type(-1) as documented in version 3.10.0 - */ - constexpr subtype_type subtype() const noexcept - { - return m_has_subtype ? m_subtype : subtype_type(-1); - } - - /*! - @brief return whether the value has a subtype - - @return whether the value has a subtype - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa see @ref subtype() -- return the binary subtype - @sa see @ref set_subtype() -- sets the binary subtype - @sa see @ref clear_subtype() -- clears the binary subtype - - @since version 3.8.0 - */ - constexpr bool has_subtype() const noexcept - { - return m_has_subtype; - } - - /*! - @brief clears the binary subtype - - Clears the binary subtype and flags the value as not having a subtype, which - has implications for serialization; for instance MessagePack will prefer the - bin family over the ext family. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. - - @sa see @ref subtype() -- return the binary subtype - @sa see @ref set_subtype() -- sets the binary subtype - @sa see @ref has_subtype() -- returns whether or not the binary value has a - subtype - - @since version 3.8.0 - */ - void clear_subtype() noexcept - { - m_subtype = 0; - m_has_subtype = false; - } - - private: - subtype_type m_subtype = 0; - bool m_has_subtype = false; -}; - -} // namespace nlohmann - -// #include - -// #include - -// #include - -// #include - - -#include // uint8_t -#include // size_t -#include // hash - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ - -// boost::hash_combine -inline std::size_t combine(std::size_t seed, std::size_t h) noexcept -{ - seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); - return seed; +constexpr const auto& to_json = detail::static_const::value; } - -/*! -@brief hash a JSON value - -The hash function tries to rely on std::hash where possible. Furthermore, the -type of the JSON value is taken into account to have different hash values for -null, 0, 0U, and false, etc. - -@tparam BasicJsonType basic_json specialization -@param j JSON value to hash -@return hash value of j -*/ -template -std::size_t hash(const BasicJsonType& j) -{ - using string_t = typename BasicJsonType::string_t; - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - - const auto type = static_cast(j.type()); - switch (j.type()) - { - case BasicJsonType::value_t::null: - case BasicJsonType::value_t::discarded: - { - return combine(type, 0); - } - - case BasicJsonType::value_t::object: - { - auto seed = combine(type, j.size()); - for (const auto& element : j.items()) - { - const auto h = std::hash {}(element.key()); - seed = combine(seed, h); - seed = combine(seed, hash(element.value())); - } - return seed; - } - - case BasicJsonType::value_t::array: - { - auto seed = combine(type, j.size()); - for (const auto& element : j) - { - seed = combine(seed, hash(element)); - } - return seed; - } - - case BasicJsonType::value_t::string: - { - const auto h = std::hash {}(j.template get_ref()); - return combine(type, h); - } - - case BasicJsonType::value_t::boolean: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_integer: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_unsigned: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::number_float: - { - const auto h = std::hash {}(j.template get()); - return combine(type, h); - } - - case BasicJsonType::value_t::binary: - { - auto seed = combine(type, j.get_binary().size()); - const auto h = std::hash {}(j.get_binary().has_subtype()); - seed = combine(seed, h); - seed = combine(seed, static_cast(j.get_binary().subtype())); - for (const auto byte : j.get_binary()) - { - seed = combine(seed, std::hash {}(byte)); - } - return seed; - } - - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE - return 0; // LCOV_EXCL_LINE - } } -} // namespace detail -} // namespace nlohmann - -// #include - - -#include // generate_n -#include // array -#include // ldexp -#include // size_t -#include // uint8_t, uint16_t, uint32_t, uint64_t -#include // snprintf -#include // memcpy -#include // back_inserter -#include // numeric_limits -#include // char_traits, string -#include // make_pair, move -#include // vector - -// #include - // #include -#include // array +#include // assert #include // size_t #include // strlen +#include // istream #include // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include // shared_ptr, make_shared, addressof #include // accumulate @@ -5339,13 +1847,6 @@ std::size_t hash(const BasicJsonType& j) #include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include // pair, declval -#ifndef JSON_NO_IO - #include // FILE * - #include // istream -#endif // JSON_NO_IO - -// #include - // #include @@ -5354,44 +1855,32 @@ namespace nlohmann namespace detail { /// the supported input formats -enum class input_format_t { json, cbor, msgpack, ubjson, bson }; +enum class input_format_t { json, cbor, msgpack, ubjson }; //////////////////// // input adapters // //////////////////// -#ifndef JSON_NO_IO /*! -Input adapter for stdio file access. This adapter read only 1 byte and do not use any - buffer. This adapter is a very low level adapter. +@brief abstract input adapter interface + +Produces a stream of std::char_traits::int_type characters from a +std::istream, a buffer, or some other input type. Accepts the return of +exactly one non-EOF character for future input. The int_type characters +returned consist of all valid char values as positive values (typically +unsigned char), plus an EOF value outside that range, specified by the value +of the function std::char_traits::eof(). This value is typically -1, but +could be any arbitrary value which is not a valid char value. */ -class file_input_adapter +struct input_adapter_protocol { - public: - using char_type = char; - - JSON_HEDLEY_NON_NULL(2) - explicit file_input_adapter(std::FILE* f) noexcept - : m_file(f) - {} - - // make class move-only - file_input_adapter(const file_input_adapter&) = delete; - file_input_adapter(file_input_adapter&&) noexcept = default; - file_input_adapter& operator=(const file_input_adapter&) = delete; - file_input_adapter& operator=(file_input_adapter&&) = delete; - ~file_input_adapter() = default; - - std::char_traits::int_type get_character() noexcept - { - return std::fgetc(m_file); - } - - private: - /// the file pointer to read from - std::FILE* m_file; + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; + virtual ~input_adapter_protocol() = default; }; +/// a type to simplify interfaces +using input_adapter_t = std::shared_ptr; /*! Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at @@ -5402,169 +1891,103 @@ characters following those used in parsing the JSON input. Clears the std::istream flags; any input errors (e.g., EOF) will be detected by the first subsequent call for input from the std::istream. */ -class input_stream_adapter +class input_stream_adapter : public input_adapter_protocol { public: - using char_type = char; - - ~input_stream_adapter() + ~input_stream_adapter() override { // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags, except eof - if (is != nullptr) - { - is->clear(is->rdstate() & std::ios::eofbit); - } + // maintain ifstream flags + is.clear(); } explicit input_stream_adapter(std::istream& i) - : is(&i), sb(i.rdbuf()) + : is(i), sb(*i.rdbuf()) {} // delete because of pointer members input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter& operator=(input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&&) = delete; - - input_stream_adapter(input_stream_adapter&& rhs) noexcept - : is(rhs.is), sb(rhs.sb) - { - rhs.is = nullptr; - rhs.sb = nullptr; - } // std::istream/std::streambuf use std::char_traits::to_int_type, to // ensure that std::char_traits::eof() and the character 0xFF do not // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() + std::char_traits::int_type get_character() override { - auto res = sb->sbumpc(); - // set eof manually, as we don't use the istream interface. - if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) - { - is->clear(is->rdstate() | std::ios::eofbit); - } - return res; + return sb.sbumpc(); } private: /// the associated input stream - std::istream* is = nullptr; - std::streambuf* sb = nullptr; + std::istream& is; + std::streambuf& sb; }; -#endif // JSON_NO_IO -// General-purpose iterator-based adapter. It might not be as fast as -// theoretically possible for some containers, but it is extremely versatile. -template -class iterator_input_adapter +/// input adapter for buffer input +class input_buffer_adapter : public input_adapter_protocol { public: - using char_type = typename std::iterator_traits::value_type; - - iterator_input_adapter(IteratorType first, IteratorType last) - : current(std::move(first)), end(std::move(last)) + input_buffer_adapter(const char* b, const std::size_t l) + : cursor(b), limit(b + l) {} - typename std::char_traits::int_type get_character() + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; + input_buffer_adapter& operator=(input_buffer_adapter&) = delete; + + std::char_traits::int_type get_character() noexcept override { - if (JSON_HEDLEY_LIKELY(current != end)) + if (JSON_LIKELY(cursor < limit)) { - auto result = std::char_traits::to_int_type(*current); - std::advance(current, 1); - return result; + return std::char_traits::to_int_type(*(cursor++)); } - return std::char_traits::eof(); + return std::char_traits::eof(); } private: - IteratorType current; - IteratorType end; - - template - friend struct wide_string_input_helper; - - bool empty() const - { - return current == end; - } + /// pointer to the current character + const char* cursor; + /// pointer past the last character + const char* const limit; }; - -template -struct wide_string_input_helper; - -template -struct wide_string_input_helper +template +class wide_string_input_adapter : public input_adapter_protocol { - // UTF-32 - static void fill_buffer(BaseInputAdapter& input, - std::array::int_type, 4>& utf8_bytes, - size_t& utf8_bytes_index, - size_t& utf8_bytes_filled) + public: + explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} + + std::char_traits::int_type get_character() noexcept override { - utf8_bytes_index = 0; - - if (JSON_HEDLEY_UNLIKELY(input.empty())) + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const auto wc = input.get_character(); - - // UTF-32 to UTF-8 encoding - if (wc < 0x80) + if (sizeof(typename WideStringType::value_type) == 2) { - utf8_bytes[0] = static_cast::int_type>(wc); - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); - utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); - utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); - utf8_bytes_filled = 4; + fill_buffer_utf16(); } else { - // unknown character - utf8_bytes[0] = static_cast::int_type>(wc); - utf8_bytes_filled = 1; + fill_buffer_utf32(); } - } - } -}; -template -struct wide_string_input_helper -{ - // UTF-16 - static void fill_buffer(BaseInputAdapter& input, - std::array::int_type, 4>& utf8_bytes, - size_t& utf8_bytes_index, - size_t& utf8_bytes_filled) + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index == 0); + } + + // use buffer + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + void fill_buffer_utf16() { utf8_bytes_index = 0; - if (JSON_HEDLEY_UNLIKELY(input.empty())) + if (current_wchar == str.size()) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -5572,84 +1995,106 @@ struct wide_string_input_helper else { // get the current character - const auto wc = input.get_character(); + const int wc = static_cast(str[current_wchar++]); // UTF-16 to UTF-8 encoding if (wc < 0x80) { - utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes[0] = wc; utf8_bytes_filled = 1; } else if (wc <= 0x7FF) { - utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); - utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes[0] = 0xC0 | ((wc >> 6)); + utf8_bytes[1] = 0x80 | (wc & 0x3F); utf8_bytes_filled = 2; } - else if (0xD800 > wc || wc >= 0xE000) + else if (0xD800 > wc or wc >= 0xE000) { - utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes[0] = 0xE0 | ((wc >> 12)); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); utf8_bytes_filled = 3; } else { - if (JSON_HEDLEY_UNLIKELY(!input.empty())) + if (current_wchar < str.size()) { - const auto wc2 = static_cast(input.get_character()); - const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); - utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); - utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); - utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); - utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); + const int wc2 = static_cast(str[current_wchar++]); + const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); + utf8_bytes[0] = 0xf0 | (charcode >> 18); + utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (charcode & 0x3F); utf8_bytes_filled = 4; } else { - utf8_bytes[0] = static_cast::int_type>(wc); + // unknown character + ++current_wchar; + utf8_bytes[0] = wc; utf8_bytes_filled = 1; } } } } -}; -// Wraps another input apdater to convert wide character types into individual bytes. -template -class wide_string_input_adapter -{ - public: - using char_type = char; - - wide_string_input_adapter(BaseInputAdapter base) - : base_adapter(base) {} - - typename std::char_traits::int_type get_character() noexcept + void fill_buffer_utf32() { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) + utf8_bytes_index = 0; + + if (current_wchar == str.size()) { - fill_buffer(); - - JSON_ASSERT(utf8_bytes_filled > 0); - JSON_ASSERT(utf8_bytes_index == 0); + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; } + else + { + // get the current character + const int wc = static_cast(str[current_wchar++]); - // use buffer - JSON_ASSERT(utf8_bytes_filled > 0); - JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); + utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + } } private: - BaseInputAdapter base_adapter; + /// the wstring to process + const WideStringType& str; - template - void fill_buffer() - { - wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); - } + /// index of the current wchar in str + std::size_t current_wchar = 0; /// a buffer for UTF-8 bytes std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; @@ -5660,893 +2105,126 @@ class wide_string_input_adapter std::size_t utf8_bytes_filled = 0; }; - -template -struct iterator_input_adapter_factory -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using adapter_type = iterator_input_adapter; - - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(std::move(first), std::move(last)); - } -}; - -template -struct is_iterator_of_multibyte -{ - using value_type = typename std::iterator_traits::value_type; - enum - { - value = sizeof(value_type) > 1 - }; -}; - -template -struct iterator_input_adapter_factory::value>> -{ - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using base_adapter_type = iterator_input_adapter; - using adapter_type = wide_string_input_adapter; - - static adapter_type create(IteratorType first, IteratorType last) - { - return adapter_type(base_adapter_type(std::move(first), std::move(last))); - } -}; - -// General purpose iterator-based input -template -typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) -{ - using factory_type = iterator_input_adapter_factory; - return factory_type::create(first, last); -} - -// Convenience shorthand from container to iterator -// Enables ADL on begin(container) and end(container) -// Encloses the using declarations in namespace for not to leak them to outside scope - -namespace container_input_adapter_factory_impl -{ - -using std::begin; -using std::end; - -template -struct container_input_adapter_factory {}; - -template -struct container_input_adapter_factory< ContainerType, - void_t()), end(std::declval()))>> - { - using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); - - static adapter_type create(const ContainerType& container) -{ - return input_adapter(begin(container), end(container)); -} - }; - -} // namespace container_input_adapter_factory_impl - -template -typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) -{ - return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); -} - -#ifndef JSON_NO_IO -// Special cases with fast paths -inline file_input_adapter input_adapter(std::FILE* file) -{ - return file_input_adapter(file); -} - -inline input_stream_adapter input_adapter(std::istream& stream) -{ - return input_stream_adapter(stream); -} - -inline input_stream_adapter input_adapter(std::istream&& stream) -{ - return input_stream_adapter(stream); -} -#endif // JSON_NO_IO - -using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); - -// Null-delimited strings, and the like. -template < typename CharT, - typename std::enable_if < - std::is_pointer::value&& - !std::is_array::value&& - std::is_integral::type>::value&& - sizeof(typename std::remove_pointer::type) == 1, - int >::type = 0 > -contiguous_bytes_input_adapter input_adapter(CharT b) -{ - auto length = std::strlen(reinterpret_cast(b)); - const auto* ptr = reinterpret_cast(b); - return input_adapter(ptr, ptr + length); -} - -template -auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) -{ - return input_adapter(array, array + N); -} - -// This class only handles inputs of input_buffer_adapter type. -// It's required so that expressions like {ptr, len} can be implicitely casted -// to the correct adapter. -class span_input_adapter +class input_adapter { public: - template < typename CharT, - typename std::enable_if < - std::is_pointer::value&& - std::is_integral::type>::value&& - sizeof(typename std::remove_pointer::type) == 1, - int >::type = 0 > - span_input_adapter(CharT b, std::size_t l) - : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} + // native support + /// input adapter for input stream + input_adapter(std::istream& i) + : ia(std::make_shared(i)) {} + + /// input adapter for input stream + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + + input_adapter(const std::wstring& ws) + : ia(std::make_shared>(ws)) {} + + input_adapter(const std::u16string& ws) + : ia(std::make_shared>(ws)) {} + + input_adapter(const std::u32string& ws) + : ia(std::make_shared>(ws)) {} + + /// input adapter for buffer + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} + + // derived support + + /// input adapter for string literal + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b) + : input_adapter(reinterpret_cast(b), + std::strlen(reinterpret_cast(b))) {} + + /// input adapter for iterator range with contiguous storage template::iterator_category, std::random_access_iterator_tag>::value, + std::is_same::iterator_category, std::random_access_iterator_tag>::value, int>::type = 0> - span_input_adapter(IteratorType first, IteratorType last) - : ia(input_adapter(first, last)) {} - - contiguous_bytes_input_adapter&& get() + input_adapter(IteratorType first, IteratorType last) { - return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + const auto len = static_cast(std::distance(first, last)); + if (JSON_LIKELY(len > 0)) + { + // there is at least one element: use the address of first + ia = std::make_shared(reinterpret_cast(&(*first)), len); + } + else + { + // the address of first cannot be used: use nullptr + ia = std::make_shared(nullptr, len); + } + } + + /// input adapter for array + template + input_adapter(T (&array)[N]) + : input_adapter(std::begin(array), std::end(array)) {} + + /// input adapter for contiguous container + template::value and + std::is_base_of()))>::iterator_category>::value, + int>::type = 0> + input_adapter(const ContiguousContainer& c) + : input_adapter(std::begin(c), std::end(c)) {} + + operator input_adapter_t() + { + return ia; } private: - contiguous_bytes_input_adapter ia; + /// the actual adapter + input_adapter_t ia = nullptr; }; -} // namespace detail -} // namespace nlohmann - -// #include - - -#include -#include // string -#include // move -#include // vector - -// #include - -// #include - - -namespace nlohmann -{ - -/*! -@brief SAX interface - -This class describes the SAX interface used by @ref nlohmann::json::sax_parse. -Each function is called in different situations while the input is parsed. The -boolean return value informs the parser whether to continue processing the -input. -*/ -template -struct json_sax -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @brief a null value was read - @return whether parsing should proceed - */ - virtual bool null() = 0; - - /*! - @brief a boolean value was read - @param[in] val boolean value - @return whether parsing should proceed - */ - virtual bool boolean(bool val) = 0; - - /*! - @brief an integer number was read - @param[in] val integer value - @return whether parsing should proceed - */ - virtual bool number_integer(number_integer_t val) = 0; - - /*! - @brief an unsigned integer number was read - @param[in] val unsigned integer value - @return whether parsing should proceed - */ - virtual bool number_unsigned(number_unsigned_t val) = 0; - - /*! - @brief an floating-point number was read - @param[in] val floating-point value - @param[in] s raw token value - @return whether parsing should proceed - */ - virtual bool number_float(number_float_t val, const string_t& s) = 0; - - /*! - @brief a string was read - @param[in] val string value - @return whether parsing should proceed - @note It is safe to move the passed string. - */ - virtual bool string(string_t& val) = 0; - - /*! - @brief a binary string was read - @param[in] val binary value - @return whether parsing should proceed - @note It is safe to move the passed binary. - */ - virtual bool binary(binary_t& val) = 0; - - /*! - @brief the beginning of an object was read - @param[in] elements number of object elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_object(std::size_t elements) = 0; - - /*! - @brief an object key was read - @param[in] val object key - @return whether parsing should proceed - @note It is safe to move the passed string. - */ - virtual bool key(string_t& val) = 0; - - /*! - @brief the end of an object was read - @return whether parsing should proceed - */ - virtual bool end_object() = 0; - - /*! - @brief the beginning of an array was read - @param[in] elements number of array elements or -1 if unknown - @return whether parsing should proceed - @note binary formats may report the number of elements - */ - virtual bool start_array(std::size_t elements) = 0; - - /*! - @brief the end of an array was read - @return whether parsing should proceed - */ - virtual bool end_array() = 0; - - /*! - @brief a parse error occurred - @param[in] position the position in the input where the error occurs - @param[in] last_token the last read token - @param[in] ex an exception object describing the error - @return whether parsing should proceed (must return false) - */ - virtual bool parse_error(std::size_t position, - const std::string& last_token, - const detail::exception& ex) = 0; - - json_sax() = default; - json_sax(const json_sax&) = default; - json_sax(json_sax&&) noexcept = default; - json_sax& operator=(const json_sax&) = default; - json_sax& operator=(json_sax&&) noexcept = default; - virtual ~json_sax() = default; -}; - - -namespace detail -{ -/*! -@brief SAX implementation to create a JSON value from SAX events - -This class implements the @ref json_sax interface and processes the SAX events -to create a JSON value which makes it basically a DOM parser. The structure or -hierarchy of the JSON value is managed by the stack `ref_stack` which contains -a pointer to the respective array or object for each recursion depth. - -After successful parsing, the value that is passed by reference to the -constructor contains the parsed value. - -@tparam BasicJsonType the JSON type -*/ -template -class json_sax_dom_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - /*! - @param[in,out] r reference to a JSON value that is manipulated while - parsing - @param[in] allow_exceptions_ whether parse errors yield exceptions - */ - explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) - : root(r), allow_exceptions(allow_exceptions_) - {} - - // make class move-only - json_sax_dom_parser(const json_sax_dom_parser&) = delete; - json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; - json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - // add null at given key and store the reference for later - object_element = &(ref_stack.back()->m_value.object->operator[](val)); - return true; - } - - bool end_object() - { - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - bool start_array(std::size_t len) - { - ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool end_array() - { - ref_stack.back()->set_parents(); - ref_stack.pop_back(); - return true; - } - - template - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - */ - template - JSON_HEDLEY_RETURNS_NON_NULL - BasicJsonType* handle_value(Value&& v) - { - if (ref_stack.empty()) - { - root = BasicJsonType(std::forward(v)); - return &root; - } - - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(std::forward(v)); - return &(ref_stack.back()->m_value.array->back()); - } - - JSON_ASSERT(ref_stack.back()->is_object()); - JSON_ASSERT(object_element); - *object_element = BasicJsonType(std::forward(v)); - return object_element; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector ref_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; -}; - -template -class json_sax_dom_callback_parser -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - using parser_callback_t = typename BasicJsonType::parser_callback_t; - using parse_event_t = typename BasicJsonType::parse_event_t; - - json_sax_dom_callback_parser(BasicJsonType& r, - const parser_callback_t cb, - const bool allow_exceptions_ = true) - : root(r), callback(cb), allow_exceptions(allow_exceptions_) - { - keep_stack.push_back(true); - } - - // make class move-only - json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; - json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~json_sax_dom_callback_parser() = default; - - bool null() - { - handle_value(nullptr); - return true; - } - - bool boolean(bool val) - { - handle_value(val); - return true; - } - - bool number_integer(number_integer_t val) - { - handle_value(val); - return true; - } - - bool number_unsigned(number_unsigned_t val) - { - handle_value(val); - return true; - } - - bool number_float(number_float_t val, const string_t& /*unused*/) - { - handle_value(val); - return true; - } - - bool string(string_t& val) - { - handle_value(val); - return true; - } - - bool binary(binary_t& val) - { - handle_value(std::move(val)); - return true; - } - - bool start_object(std::size_t len) - { - // check callback for object start - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::object, true); - ref_stack.push_back(val.second); - - // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool key(string_t& val) - { - BasicJsonType k = BasicJsonType(val); - - // check callback for key - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); - key_keep_stack.push_back(keep); - - // add discarded value at given key and store the reference for later - if (keep && ref_stack.back()) - { - object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); - } - - return true; - } - - bool end_object() - { - if (ref_stack.back()) - { - if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) - { - // discard object - *ref_stack.back() = discarded; - } - else - { - ref_stack.back()->set_parents(); - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) - { - // remove discarded value - for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) - { - if (it->is_discarded()) - { - ref_stack.back()->erase(it); - break; - } - } - } - - return true; - } - - bool start_array(std::size_t len) - { - const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); - keep_stack.push_back(keep); - - auto val = handle_value(BasicJsonType::value_t::array, true); - ref_stack.push_back(val.second); - - // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) - { - JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); - } - - return true; - } - - bool end_array() - { - bool keep = true; - - if (ref_stack.back()) - { - keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); - if (keep) - { - ref_stack.back()->set_parents(); - } - else - { - // discard array - *ref_stack.back() = discarded; - } - } - - JSON_ASSERT(!ref_stack.empty()); - JSON_ASSERT(!keep_stack.empty()); - ref_stack.pop_back(); - keep_stack.pop_back(); - - // remove discarded value - if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->pop_back(); - } - - return true; - } - - template - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, - const Exception& ex) - { - errored = true; - static_cast(ex); - if (allow_exceptions) - { - JSON_THROW(ex); - } - return false; - } - - constexpr bool is_errored() const - { - return errored; - } - - private: - /*! - @param[in] v value to add to the JSON value we build during parsing - @param[in] skip_callback whether we should skip calling the callback - function; this is required after start_array() and - start_object() SAX events, because otherwise we would call the - callback function with an empty array or object, respectively. - - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - - @return pair of boolean (whether value should be kept) and pointer (to the - passed value in the ref_stack hierarchy; nullptr if not kept) - */ - template - std::pair handle_value(Value&& v, const bool skip_callback = false) - { - JSON_ASSERT(!keep_stack.empty()); - - // do not handle this value if we know it would be added to a discarded - // container - if (!keep_stack.back()) - { - return {false, nullptr}; - } - - // create value - auto value = BasicJsonType(std::forward(v)); - - // check callback - const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); - - // do not handle this value if we just learnt it shall be discarded - if (!keep) - { - return {false, nullptr}; - } - - if (ref_stack.empty()) - { - root = std::move(value); - return {true, &root}; - } - - // skip this value if we already decided to skip the parent - // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) - if (!ref_stack.back()) - { - return {false, nullptr}; - } - - // we now only expect arrays and objects - JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); - - // array - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(std::move(value)); - return {true, &(ref_stack.back()->m_value.array->back())}; - } - - // object - JSON_ASSERT(ref_stack.back()->is_object()); - // check if we should store an element for the current key - JSON_ASSERT(!key_keep_stack.empty()); - const bool store_element = key_keep_stack.back(); - key_keep_stack.pop_back(); - - if (!store_element) - { - return {false, nullptr}; - } - - JSON_ASSERT(object_element); - *object_element = std::move(value); - return {true, object_element}; - } - - /// the parsed JSON value - BasicJsonType& root; - /// stack to model hierarchy of values - std::vector ref_stack {}; - /// stack to manage which values to keep - std::vector keep_stack {}; - /// stack to manage which object keys to keep - std::vector key_keep_stack {}; - /// helper to hold the reference for the next object element - BasicJsonType* object_element = nullptr; - /// whether a syntax error occurred - bool errored = false; - /// callback function - const parser_callback_t callback = nullptr; - /// whether to throw exceptions in case of errors - const bool allow_exceptions = true; - /// a discarded value for the callback - BasicJsonType discarded = BasicJsonType::value_t::discarded; -}; - -template -class json_sax_acceptor -{ - public: - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using binary_t = typename BasicJsonType::binary_t; - - bool null() - { - return true; - } - - bool boolean(bool /*unused*/) - { - return true; - } - - bool number_integer(number_integer_t /*unused*/) - { - return true; - } - - bool number_unsigned(number_unsigned_t /*unused*/) - { - return true; - } - - bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) - { - return true; - } - - bool string(string_t& /*unused*/) - { - return true; - } - - bool binary(binary_t& /*unused*/) - { - return true; - } - - bool start_object(std::size_t /*unused*/ = std::size_t(-1)) - { - return true; - } - - bool key(string_t& /*unused*/) - { - return true; - } - - bool end_object() - { - return true; - } - - bool start_array(std::size_t /*unused*/ = std::size_t(-1)) - { - return true; - } - - bool end_array() - { - return true; - } - - bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) - { - return false; - } -}; -} // namespace detail - -} // namespace nlohmann +} +} // #include -#include // array #include // localeconv #include // size_t -#include // snprintf #include // strtof, strtod, strtold, strtoll, strtoull +#include // snprintf #include // initializer_list #include // char_traits, string -#include // move #include // vector -// #include - -// #include - // #include +// #include + namespace nlohmann { @@ -6556,9 +2234,19 @@ namespace detail // lexer // /////////// +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ template -class lexer_base +class lexer { + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + public: /// token types for the parser enum class token_type @@ -6583,8 +2271,6 @@ class lexer_base }; /// return name of values of type token_type (only used for errors) - JSON_HEDLEY_RETURNS_NON_NULL - JSON_HEDLEY_CONST static const char* token_type_name(const token_type t) noexcept { switch (t) @@ -6599,9 +2285,9 @@ class lexer_base return "null literal"; case token_type::value_string: return "string literal"; - case token_type::value_unsigned: - case token_type::value_integer: - case token_type::value_float: + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: return "number literal"; case token_type::begin_array: return "'['"; @@ -6627,37 +2313,13 @@ class lexer_base // LCOV_EXCL_STOP } } -}; -/*! -@brief lexical analysis -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer : public lexer_base -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - using char_type = typename InputAdapterType::char_type; - using char_int_type = typename std::char_traits::int_type; - - public: - using token_type = typename lexer_base::token_type; - - explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept - : ia(std::move(adapter)) - , ignore_comments(ignore_comments_) - , decimal_point_char(static_cast(get_decimal_point())) - {} + explicit lexer(detail::input_adapter_t&& adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} // delete because of pointer members lexer(const lexer&) = delete; - lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) lexer& operator=(lexer&) = delete; - lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) - ~lexer() = default; private: ///////////////////// @@ -6665,11 +2327,10 @@ class lexer : public lexer_base ///////////////////// /// return the locale-dependent decimal point - JSON_HEDLEY_PURE static char get_decimal_point() noexcept { - const auto* loc = localeconv(); - JSON_ASSERT(loc != nullptr); + const auto loc = localeconv(); + assert(loc != nullptr); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); } @@ -6695,25 +2356,25 @@ class lexer : public lexer_base int get_codepoint() { // this function only makes sense after reading `\u` - JSON_ASSERT(current == 'u'); + assert(current == 'u'); int codepoint = 0; - const auto factors = { 12u, 8u, 4u, 0u }; + const auto factors = { 12, 8, 4, 0 }; for (const auto factor : factors) { get(); - if (current >= '0' && current <= '9') + if (current >= '0' and current <= '9') { - codepoint += static_cast((static_cast(current) - 0x30u) << factor); + codepoint += ((current - 0x30) << factor); } - else if (current >= 'A' && current <= 'F') + else if (current >= 'A' and current <= 'F') { - codepoint += static_cast((static_cast(current) - 0x37u) << factor); + codepoint += ((current - 0x37) << factor); } - else if (current >= 'a' && current <= 'f') + else if (current >= 'a' and current <= 'f') { - codepoint += static_cast((static_cast(current) - 0x57u) << factor); + codepoint += ((current - 0x57) << factor); } else { @@ -6721,7 +2382,7 @@ class lexer : public lexer_base } } - JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); + assert(0x0000 <= codepoint and codepoint <= 0xFFFF); return codepoint; } @@ -6740,15 +2401,15 @@ class lexer : public lexer_base @return true if and only if no range violation was detected */ - bool next_byte_in_range(std::initializer_list ranges) + bool next_byte_in_range(std::initializer_list ranges) { - JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); + assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); add(current); for (auto range = ranges.begin(); range != ranges.end(); ++range) { get(); - if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) + if (JSON_LIKELY(*range <= current and current <= *(++range))) { add(current); } @@ -6765,7 +2426,7 @@ class lexer : public lexer_base /*! @brief scan a string literal - This function scans a string according to Sect. 7 of RFC 8259. While + This function scans a string according to Sect. 7 of RFC 7159. While scanning, bytes are escaped and copied into buffer token_buffer. Then the function returns successfully, token_buffer is *not* null-terminated (as it may contain \0 bytes), and token_buffer.size() is the number of bytes in the @@ -6783,7 +2444,7 @@ class lexer : public lexer_base reset(); // we entered the function by reading an open quote - JSON_ASSERT(current == '\"'); + assert(current == '\"'); while (true) { @@ -6791,7 +2452,7 @@ class lexer : public lexer_base switch (get()) { // end of file while parsing string - case std::char_traits::eof(): + case std::char_traits::eof(): { error_message = "invalid string: missing closing quote"; return token_type::parse_error; @@ -6847,55 +2508,55 @@ class lexer : public lexer_base const int codepoint1 = get_codepoint(); int codepoint = codepoint1; // start with codepoint1 - if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) + if (JSON_UNLIKELY(codepoint1 == -1)) { error_message = "invalid string: '\\u' must be followed by 4 hex digits"; return token_type::parse_error; } // check if code point is a high surrogate - if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) { // expect next \uxxxx entry - if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) + if (JSON_LIKELY(get() == '\\' and get() == 'u')) { const int codepoint2 = get_codepoint(); - if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) + if (JSON_UNLIKELY(codepoint2 == -1)) { error_message = "invalid string: '\\u' must be followed by 4 hex digits"; return token_type::parse_error; } // check if codepoint2 is a low surrogate - if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) { // overwrite codepoint - codepoint = static_cast( - // high surrogate occupies the most significant 22 bits - (static_cast(codepoint1) << 10u) - // low surrogate occupies the least significant 15 bits - + static_cast(codepoint2) - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00u); + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; } else { - error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; return token_type::parse_error; } } else { - error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; return token_type::parse_error; } } else { - if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) { error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; return token_type::parse_error; @@ -6903,34 +2564,34 @@ class lexer : public lexer_base } // result of the above calculation yields a proper codepoint - JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); // translate codepoint into bytes if (codepoint < 0x80) { // 1-byte characters: 0xxxxxxx (ASCII) - add(static_cast(codepoint)); + add(codepoint); } else if (codepoint <= 0x7FF) { // 2-byte characters: 110xxxxx 10xxxxxx - add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); - add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); } else if (codepoint <= 0xFFFF) { // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); - add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); - add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); } else { // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); - add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); - add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); - add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); } break; @@ -6947,194 +2608,39 @@ class lexer : public lexer_base // invalid control characters case 0x00: - { - error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; - return token_type::parse_error; - } - case 0x01: - { - error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; - return token_type::parse_error; - } - case 0x02: - { - error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; - return token_type::parse_error; - } - case 0x03: - { - error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; - return token_type::parse_error; - } - case 0x04: - { - error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; - return token_type::parse_error; - } - case 0x05: - { - error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; - return token_type::parse_error; - } - case 0x06: - { - error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; - return token_type::parse_error; - } - case 0x07: - { - error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; - return token_type::parse_error; - } - case 0x08: - { - error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; - return token_type::parse_error; - } - case 0x09: - { - error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; - return token_type::parse_error; - } - case 0x0A: - { - error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; - return token_type::parse_error; - } - case 0x0B: - { - error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; - return token_type::parse_error; - } - case 0x0C: - { - error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; - return token_type::parse_error; - } - case 0x0D: - { - error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; - return token_type::parse_error; - } - case 0x0E: - { - error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; - return token_type::parse_error; - } - case 0x0F: - { - error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; - return token_type::parse_error; - } - case 0x10: - { - error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; - return token_type::parse_error; - } - case 0x11: - { - error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; - return token_type::parse_error; - } - case 0x12: - { - error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; - return token_type::parse_error; - } - case 0x13: - { - error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; - return token_type::parse_error; - } - case 0x14: - { - error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; - return token_type::parse_error; - } - case 0x15: - { - error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; - return token_type::parse_error; - } - case 0x16: - { - error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; - return token_type::parse_error; - } - case 0x17: - { - error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; - return token_type::parse_error; - } - case 0x18: - { - error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; - return token_type::parse_error; - } - case 0x19: - { - error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; - return token_type::parse_error; - } - case 0x1A: - { - error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; - return token_type::parse_error; - } - case 0x1B: - { - error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; - return token_type::parse_error; - } - case 0x1C: - { - error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; - return token_type::parse_error; - } - case 0x1D: - { - error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; - return token_type::parse_error; - } - case 0x1E: - { - error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; - return token_type::parse_error; - } - case 0x1F: { - error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; + error_message = "invalid string: control character must be escaped"; return token_type::parse_error; } @@ -7270,7 +2776,7 @@ class lexer : public lexer_base case 0xDE: case 0xDF: { - if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) + if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) { return token_type::parse_error; } @@ -7280,7 +2786,7 @@ class lexer : public lexer_base // U+0800..U+0FFF: bytes E0 A0..BF 80..BF case 0xE0: { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -7304,7 +2810,7 @@ class lexer : public lexer_base case 0xEE: case 0xEF: { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -7314,7 +2820,7 @@ class lexer : public lexer_base // U+D000..U+D7FF: bytes ED 80..9F 80..BF case 0xED: { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -7324,7 +2830,7 @@ class lexer : public lexer_base // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF case 0xF0: { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -7336,7 +2842,7 @@ class lexer : public lexer_base case 0xF2: case 0xF3: { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -7346,7 +2852,7 @@ class lexer : public lexer_base // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF case 0xF4: { - if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) { return token_type::parse_error; } @@ -7363,90 +2869,16 @@ class lexer : public lexer_base } } - /*! - * @brief scan a comment - * @return whether comment could be scanned successfully - */ - bool scan_comment() - { - switch (get()) - { - // single-line comments skip input until a newline or EOF is read - case '/': - { - while (true) - { - switch (get()) - { - case '\n': - case '\r': - case std::char_traits::eof(): - case '\0': - return true; - - default: - break; - } - } - } - - // multi-line comments skip input until */ is read - case '*': - { - while (true) - { - switch (get()) - { - case std::char_traits::eof(): - case '\0': - { - error_message = "invalid comment; missing closing '*/'"; - return false; - } - - case '*': - { - switch (get()) - { - case '/': - return true; - - default: - { - unget(); - continue; - } - } - } - - default: - continue; - } - } - } - - // unexpected character after reading '/' - default: - { - error_message = "invalid comment; expecting '/' or '*' after '/'"; - return false; - } - } - } - - JSON_HEDLEY_NON_NULL(2) static void strtof(float& f, const char* str, char** endptr) noexcept { f = std::strtof(str, endptr); } - JSON_HEDLEY_NON_NULL(2) static void strtof(double& f, const char* str, char** endptr) noexcept { f = std::strtod(str, endptr); } - JSON_HEDLEY_NON_NULL(2) static void strtof(long double& f, const char* str, char** endptr) noexcept { f = std::strtold(str, endptr); @@ -7455,10 +2887,10 @@ class lexer : public lexer_base /*! @brief scan a number literal - This function scans a string according to Sect. 6 of RFC 8259. + This function scans a string according to Sect. 6 of RFC 7159. The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 8259. Starting in state "init", the + from the grammar described in RFC 7159. Starting in state "init", the input is read and used to determined the next state. Only state "done" accepts the number. State "error" is a trap state to model errors. In the table below, "anything" means any character but the ones listed before. @@ -7469,7 +2901,7 @@ class lexer : public lexer_base minus | zero | any1 | [error] | [error] | [error] | [error] | [error] zero | done | done | exponent | done | done | decimal1 | done any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] decimal2 | decimal2 | decimal2 | exponent | done | done | done | done exponent | any2 | any2 | [error] | sign | sign | [error] | [error] sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] @@ -7492,7 +2924,7 @@ class lexer : public lexer_base locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ - token_type scan_number() // lgtm [cpp/use-of-goto] + token_type scan_number() { // reset token_buffer to store the number's bytes reset(); @@ -7530,9 +2962,13 @@ class lexer : public lexer_base goto scan_number_any1; } - // all other characters are rejected outside scan_number() - default: // LCOV_EXCL_LINE - JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + // LCOV_EXCL_START + default: + { + // all other characters are rejected outside scan_number() + assert(false); + } + // LCOV_EXCL_STOP } scan_number_minus: @@ -7770,7 +3206,7 @@ scan_number_done: // we are done scanning a number) unget(); - char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + char* endptr = nullptr; errno = 0; // try to parse integers first and fall back to floats @@ -7779,7 +3215,7 @@ scan_number_done: const auto x = std::strtoull(token_buffer.data(), &endptr, 10); // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + assert(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -7795,7 +3231,7 @@ scan_number_done: const auto x = std::strtoll(token_buffer.data(), &endptr, 10); // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + assert(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -7812,7 +3248,7 @@ scan_number_done: strtof(value_float, token_buffer.data(), &endptr); // we checked the number format before - JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + assert(endptr == token_buffer.data() + token_buffer.size()); return token_type::value_float; } @@ -7822,14 +3258,13 @@ scan_number_done: @param[in] length the length of the passed literal text @param[in] return_type the token type to return on success */ - JSON_HEDLEY_NON_NULL(2) - token_type scan_literal(const char_type* literal_text, const std::size_t length, + token_type scan_literal(const char* literal_text, const std::size_t length, token_type return_type) { - JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); + assert(current == literal_text[0]); for (std::size_t i = 1; i < length; ++i) { - if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) + if (JSON_UNLIKELY(get() != literal_text[i])) { error_message = "invalid literal"; return token_type::parse_error; @@ -7847,7 +3282,7 @@ scan_number_done: { token_buffer.clear(); token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); + token_string.push_back(std::char_traits::to_char_type(current)); } /* @@ -7860,11 +3295,9 @@ scan_number_done: @return character read from the input */ - char_int_type get() + std::char_traits::int_type get() { - ++position.chars_read_total; - ++position.chars_read_current_line; - + ++chars_read; if (next_unget) { // just reset the next_unget variable and work with current @@ -7872,20 +3305,13 @@ scan_number_done: } else { - current = ia.get_character(); + current = ia->get_character(); } - if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + if (JSON_LIKELY(current != std::char_traits::eof())) { - token_string.push_back(std::char_traits::to_char_type(current)); + token_string.push_back(std::char_traits::to_char_type(current)); } - - if (current == '\n') - { - ++position.lines_read; - position.chars_read_current_line = 0; - } - return current; } @@ -7893,40 +3319,25 @@ scan_number_done: @brief unget current character (read it again on next get) We implement unget by setting variable next_unget to true. The input is not - changed - we just simulate ungetting by modifying chars_read_total, - chars_read_current_line, and token_string. The next call to get() will - behave as if the unget character is read again. + changed - we just simulate ungetting by modifying chars_read and + token_string. The next call to get() will behave as if the unget character + is read again. */ void unget() { next_unget = true; - - --position.chars_read_total; - - // in case we "unget" a newline, we have to also decrement the lines_read - if (position.chars_read_current_line == 0) + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) { - if (position.lines_read > 0) - { - --position.lines_read; - } - } - else - { - --position.chars_read_current_line; - } - - if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) - { - JSON_ASSERT(!token_string.empty()); + assert(token_string.size() != 0); token_string.pop_back(); } } /// add a character to token_buffer - void add(char_int_type c) + void add(int c) { - token_buffer.push_back(static_cast(c)); + token_buffer.push_back(std::char_traits::to_char_type(c)); } public: @@ -7963,9 +3374,9 @@ scan_number_done: ///////////////////// /// return position of last read token - constexpr position_t get_position() const noexcept + constexpr std::size_t get_position() const noexcept { - return position; + return chars_read; } /// return the last read token (for errors only). Will never contain EOF @@ -7977,17 +3388,17 @@ scan_number_done: std::string result; for (const auto c : token_string) { - if (static_cast(c) <= '\x1F') + if ('\x00' <= c and c <= '\x1F') { // escape control characters - std::array cs{{}}; - (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - result += cs.data(); + char cs[9]; + snprintf(cs, 9, "", static_cast(c)); + result += cs; } else { // add character as is - result.push_back(static_cast(c)); + result.push_back(c); } } @@ -7995,7 +3406,6 @@ scan_number_done: } /// return syntax error message - JSON_HEDLEY_RETURNS_NON_NULL constexpr const char* get_error_message() const noexcept { return error_message; @@ -8013,48 +3423,41 @@ scan_number_done: { if (get() == 0xEF) { - // check if we completely parse the BOM - return get() == 0xBB && get() == 0xBF; + if (get() == 0xBB and get() == 0xBF) + { + // we completely parsed the BOM + return true; + } + else + { + // after reading 0xEF, an unexpected character followed + return false; + } } - - // the first character is not the beginning of the BOM; unget it to - // process is later - unget(); - return true; - } - - void skip_whitespace() - { - do + else { - get(); + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; } - while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } token_type scan() { // initially, skip the BOM - if (position.chars_read_total == 0 && !skip_bom()) + if (chars_read == 0 and not skip_bom()) { error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; return token_type::parse_error; } // read next character and ignore whitespace - skip_whitespace(); - - // ignore comments - while (ignore_comments && current == '/') + do { - if (!scan_comment()) - { - return token_type::parse_error; - } - - // skip following whitespace - skip_whitespace(); + get(); } + while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); switch (current) { @@ -8074,20 +3477,11 @@ scan_number_done: // literals case 't': - { - std::array true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}}; - return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); - } + return scan_literal("true", 4, token_type::literal_true); case 'f': - { - std::array false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}}; - return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); - } + return scan_literal("false", 5, token_type::literal_false); case 'n': - { - std::array null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}}; - return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); - } + return scan_literal("null", 4, token_type::literal_null); // string case '\"': @@ -8110,7 +3504,7 @@ scan_number_done: // end of input (the null byte is needed when parsing from // string literals) case '\0': - case std::char_traits::eof(): + case std::char_traits::eof(): return token_type::end_of_input; // error @@ -8122,22 +3516,19 @@ scan_number_done: private: /// input adapter - InputAdapterType ia; - - /// whether comments should be ignored (true) or signaled as errors (false) - const bool ignore_comments = false; + detail::input_adapter_t ia = nullptr; /// the current character - char_int_type current = std::char_traits::eof(); + std::char_traits::int_type current = std::char_traits::eof(); /// whether the next get() call should just return current bool next_unget = false; - /// the start position of the current token - position_t position {}; + /// the number of characters read + std::size_t chars_read = 0; /// raw input token string (for error messages) - std::vector token_string {}; + std::vector token_string {}; /// buffer for variable-length tokens (numbers, strings) string_t token_buffer {}; @@ -8151,10 +3542,22 @@ scan_number_done: number_float_t value_float = 0; /// the decimal point - const char_int_type decimal_point_char = '.'; + const char decimal_point_char = '.'; }; -} // namespace detail -} // namespace nlohmann +} +} + +// #include + + +#include // assert +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move + +// #include // #include @@ -8163,10 +3566,76 @@ scan_number_done: #include // size_t #include // declval -#include // string // #include + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +using void_t = void; +} +} + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template